Запрет OutOfMemory при использовании java.nio.MappedByteBuffer - PullRequest
5 голосов
/ 18 декабря 2011

Рассмотрим приложение, которое создает 5-6 потоков, каждый поток в цикле выделяет MappedByteBuffer для размера страницы 5 Мб.

java.io.IOException: Map failed  at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:758)
Caused by: java.lang.OutOfMemoryError: Map failed
        at sun.nio.ch.FileChannelImpl.map0(Native Method)
        at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:755)

Согласно спецификации, MappedBuffer должен распоряжаться прямой памятью, как только это сам GC.Похоже, проблема в том, что MappedBuffer-ы запаздывают в GC, позже, чем закончится прямая память.

Как избежать этой ситуации?Вероятно, скажите, что MappedBuffer неявно расположен, или используйте какой-то пул MappedBuffer

.

Ответы [ 4 ]

6 голосов
/ 19 декабря 2011

Вы можете избежать необходимости запускать GC, очистив сопоставленные байтовые буферы напрямую.

public static void clean(ByteBuffer bb) {
    if(bb == null) return;
    Cleaner cleaner = ((DirectBuffer) bb).cleaner();
    if(cleaner != null) cleaner.clean();
}

Если вы вызовете это перед сбросом, у вас не будет исчерпана виртуальная память.

Возможно, вы можете смотреть на создание более крупных байтовых буферов реже (если у вас нет большого количества файлов). Создание MappedByteBuffer не является бесплатным (на некоторых машинах это занимает около 50 микросекунд)

3 голосов
/ 18 декабря 2011

В сообщении об ошибке указано «карта не выполнена», а не «пространство кучи» или «пространство permgen».Это означает, что JVM не хватает доступного адресного пространства .

См. эту ошибку в базе данных Sun, а также этот вопрос .

Первая ссылка предоставляет обходной путь (ewww), который близок к тому, что говорит вторая ссылка:

    try {
        buffer = channel.map(READ_ONLY, ofs, n);
    } catch (java.io.IOException e) {
        System.gc();
        System.runFinalization();
        buffer = channel.map(READ_ONLY, ofs, n);
    }
2 голосов
/ 18 декабря 2011

Может быть, WeakHashMap для объединения этих MappedBuffers сработает.

Но прежде чем догадываться о основной причине, я бы рекомендовал подключить ваше приложение до Visual VM 1.3.3 , со всеми установленными плагинами, так что вы можете точно увидеть, что вызывает ошибку OOM.Вы предполагаете, что эти MappedBuffers делают это, но они всего 5 МБ каждый для 5-6 потоков - всего 25-30 МБ.

Лучше иметь данные, чем догадываться.Visual VM получит это за вас.

0 голосов
/ 19 декабря 2011

MappedBuffer должен избавиться от прямой памяти, как только это сам GC

На самом деле это не говорит о том, что я могу видеть. Существует давнишний предмет «Парада жуков», в котором говорится, что никогда не выпущено.

Это говорит это:

Поэтому рекомендуется, чтобы прямые буферы были распределены в первую очередь для больших долговечных буферов

...