Фактические буферы памяти, управляемые DirectByteBuffer
, не выделяются в куче. Они размещаются с использованием Unsafe.allocateMemory, который выделяет «родную память». Поэтому увеличение или уменьшение размера кучи не поможет.
Когда G C обнаруживает, что на DirectByteBuffer
больше нет ссылки, Cleaner
используется для освобождения собственной памяти. Однако это происходит на этапе после сбора данных, поэтому, если спрос на / оборот прямых буферов слишком велик, возможно, что сборщик не сможет идти в ногу. Если это произойдет, вы получите OOME.
Что вы можете с этим поделать?
AFAIK, единственное, что вы можете сделать, это форсировать более частые сборки мусора. Но это может иметь последствия для производительности. И я не думаю, что это гарантированное решение.
Реальное решение - выбрать другой подход.
Вы видите, что вы обслуживаете множество очень больших файлов с веб-сервера, и трассировка стека показывает, что вы используете Files::readAllBytes
для загрузки их в память, а затем (предположительно) отправляете их, используя один write
. Предположительно, вы делаете это, чтобы получить максимально быстрое время загрузки. Это ошибка:
Вы связываете много памяти (многократное использование сборщика мусора и нагрузка на него. Это приводит к большему количеству запусков G C и случайным OOME. также может по-разному влиять на другие приложения на вашем сервере.
Узким местом для передачи файла является , вероятно , а не процесс чтения данных с диска. (Реальный Узким местом является обычно отправка данных через поток TCP по сети или запись их в файловую систему на стороне клиента.)
Если вы читаете Последовательно с большим файлом современная ОС Linux обычно будет использовать для чтения вперед несколько блоков дисков и удерживать блоки в буферном кеше (ОС). Это уменьшит задержку системных вызовов read
, создаваемых вашим приложением.
Таким образом, для файлов такого размера лучшей идеей является потоковая передача файла. Либо выделите большой (несколько мегабайт) ByteBuffer
и выполните чтение / запись в al oop, * 1039. * или * 104 0 * используйте копию файла, используя Files::copy(...)
( javado c), который должен позаботиться о буферизации для вас.
(Существует также возможность использования чего-либо, сопоставленного с системным вызовом Linux sendfile
. Это копирует данные из одного файлового дескриптора в другой, не записывая их в буфер пространства пользователя.)