Как избежать OutOfMemoryError при использовании байтовых буферов и NIO? - PullRequest
3 голосов
/ 26 августа 2008

Я использую ByteBuffers и FileChannels для записи двоичных данных в файл. Делая это для больших файлов или последовательно для нескольких файлов, я получаю исключение OutOfMemoryError. Я читал в другом месте, что использование Bytebuffers с NIO не работает и его следует избегать. Кто-нибудь из вас уже сталкивался с такой проблемой и нашел решение для эффективного сохранения больших объемов двоичных данных в файл в Java?

Является ли опция jvm -XX:MaxDirectMemorySize правильным выбором?

Ответы [ 6 ]

6 голосов
/ 26 августа 2008

Я бы сказал, не создавайте огромный ByteBuffer, который содержит ВСЕ данные одновременно. Создайте намного меньший ByteBuffer, заполните его данными, затем запишите эти данные в FileChannel. Затем сбросьте ByteBuffer и продолжайте, пока все данные не будут записаны.

5 голосов
/ 26 августа 2008

Ознакомьтесь с Java Mapped Byte Buffers , также известным как «прямые буферы». По сути, этот механизм использует систему подкачки виртуальной памяти ОС для «привязки» буфера непосредственно к диску. ОС будет управлять перемещением байтов на / с диска и памяти автоматически, очень быстро, и вам не придется беспокоиться об изменении параметров вашей виртуальной машины. Это также позволит вам воспользоваться преимуществами улучшенной производительности NIO по сравнению с традиционным вводом-выводом на основе Java-потока без каких-либо странных взломов.

Единственные две уловки, о которых я могу подумать:

  1. В 32-битной системе вы ограничены общим объемом 4 ГБ для всех отображенных байтовых буферов . (Это на самом деле предел для моего приложения, и теперь я работаю на 64-битных архитектурах.)
  2. Реализация является специфической для JVM и не является обязательной. Я использую Sun JVM, и нет никаких проблем, но YMMV.

Кирк Пеппердин (несколько известный гуру Java-производительности) работает с веб-сайтом www.JavaPerformanceTuning.com, на котором есть еще несколько деталей MBB: Советы по производительности NIO

1 голос
/ 26 августа 2008

Если вы обращаетесь к файлам случайным образом (прочитайте здесь, пропустите, напишите туда, вернитесь назад), у вас возникла проблема; -)

Но если вы пишете только большие файлы, вам следует серьезно рассмотреть возможность использования потоков. java.io.FileOutputStream может быть использован непосредственно для записи файла байт за байтом или обернут в любой другой поток (например, DataOutputStream, ObjectOutputStream) для удобства записи чисел с плавающей запятой, целых, строк или даже сериализуемых объектов. Подобные классы существуют для чтения файлов.

Потоки предлагают вам удобство манипулирования произвольно большими файлами в (почти) произвольно малой памяти . Они являются предпочтительным способом доступа к файловой системе в подавляющем большинстве случаев.

0 голосов
/ 26 сентября 2008

Это может зависеть от конкретного поставщика JDK и версии.

В некоторых виртуальных машинах Sun есть ошибка в GC. Нехватка прямой памяти не вызовет сборщик мусора в основной куче, но прямая память ограничена прямыми байтовыми буферами в основной куче. Если основная куча в основном пуста, они не будут собираться в течение длительного времени.

Это может обжечь вас, даже если вы сами не используете прямые буферы, поскольку JVM может создавать прямые буферы от вашего имени. Например, запись непрямого ByteBuffer в SocketChannel создает прямой буфер под крышками для использования для фактической операции ввода-вывода.

Обходной путь - использовать небольшое количество прямых буферов самостоятельно и хранить их для повторного использования.

0 голосов
/ 26 августа 2008

Использование метода TransferFrom должно помочь в этом, если вы будете писать в канал постепенно, а не все сразу, как указывают предыдущие ответы.

0 голосов
/ 26 августа 2008

Предыдущие два ответа кажутся довольно разумными. От того, будет ли работать переключатель командной строки, зависит, насколько быстро ваше использование памяти достигнет предела. Если у вас недостаточно оперативной и виртуальной памяти, чтобы хотя бы утроить объем доступной памяти, вам потребуется использовать одно из предложенных альтернативных предложений.

...