Ответ 1
Прямой буфер
A direct buffer - это кусок памяти, обычно используемый для интерфейса Java с подсистемами ввода/вывода ОС, например, как место, где ОС записывает данные, получая их из сокета или диска и из которых Java может читать напрямую.
Обмен буфером с ОС намного более эффективен, чем оригинальный подход к копированию данных из ОС в модель памяти Java, что затем приводит к тому, что данные относятся к коллекции мусора и ее неэффективности, например, к повторному копированию данных при миграции от eden → survivor → tenured → до постоянного поколения.
На скриншоте у вас есть только один буфер из 16 Кбайт прямого буфера. Java будет наращивать этот пул по мере необходимости, так что синяя область находится в верхней части блока, это всего лишь оператор, который используется до сих пор всей буферной памятью. Я не рассматриваю это как проблему.
Пул подключенных буферов
Отображенный пул буферов - это вся память, используемая Java для FileChannel экземпляров.
Каждый экземпляр FileChannel имеет буфер, совместно используемый ОС (аналогично прямому буферу со всеми преимуществами эффективности). Память по существу представляет собой окно в ОЗУ на часть файла. В зависимости от режима (чтение, запись или и то, и другое), Java может напрямую считывать и/или изменять содержимое файла, а операционная система может напрямую передавать данные или создавать измененные данные на диск.
Дополнительные преимущества этого подхода заключаются в том, что ОС может сбрасывать этот буфер непосредственно на диск по своему усмотрению, например, когда ОС выключается, а ОС может блокировать эту часть файла из других процессов на компьютере.
Снимок экрана показывает, что у вас около 680 МБ в использовании 12 объектов FileChannel. Опять же, Java будет расти, поэтому Scala нуждается в большем количестве (и JVM может получить дополнительную память от ОС), поэтому факт, что все 680MB все в использовании, не важен. Учитывая их размер, мне кажется, что программа уже оптимизирована для эффективного использования этих буферов.
Увеличение размера отображаемого пула буферов
Java выделяет память за пределами пространства сбора мусора для буферов FileChannel. Это означает, что здесь не важны обычные параметры размера кучи, такие как -Xmx
.
Размер буфера в FileChannel устанавливается с помощью метода map. Изменение этого приведет к изменению вашей программы Scala
Как только буфер достигнет порогового размера, порядка 10s-100s KB, увеличение размера буфера FileChannel может или не может повысить производительность - это зависит от того, как программа использует буфер:
- Нет. Если файл читается точно один раз из конца в конец: почти все время либо ждет диск, либо алгоритм обработки
- Может быть. Если, однако, алгоритм часто сканирует файлы, пересматривающие части много раз, увеличение размера может повысить производительность:
- При изменении или записи файла более крупный буфер может консолидировать больше записей в один флеш.
- Если вы читаете файл, операционная система, скорее всего, уже кэширует файл (кэш диска), и поэтому любая прибыль может быть незначительной. Чрезмерное увеличение размера JVM может снизить производительность, уменьшив размер эффективного кэша диска.
- В любом случае приложение должно быть специально закодировано для получения каких-либо преимуществ, например, путем реализации его собственного указателя логической записи в кеш.
Попробуйте профилировать приложение и ищите ожидания ввода-вывода (Jprofiler и YourKit хороши в этом). Возможно, что файл ввода-вывода на самом деле не проблема - не жертва преждевременная оптимизация. Если ожидания ввода-вывода составляют значительную часть общего истекшего времени, возможно, стоит попробовать увеличить размер буфера
Дополнительная информация
https://blogs.oracle.com/alanb/entry/monitoring_direct_buffers
Также имейте в виду, что в JVM имеется сообщение об ошибке, указывающее, что FileChannel не подходит для выпуска памяти. Он подробно описан в Предотвратить OutOfMemory при использовании java.nio.MappedByteBuffer