Сведения о вопросе

1234123213

11:38, 2nd August, 2020

Теги

java   nio   bytebuffer   filechannel    

Как избежать OutOfMemoryError при использовании Bytebuffers и NIO?

Просмотров: 413   Ответов: 6

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

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



  Сведения об ответе

dumai

01:32, 10th August, 2020

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


  Сведения об ответе

PIRLO

03:56, 18th August, 2020

Проверьте сопоставленные байтовые буферы Java, также известные как 'direct buffers'. В основном, этот механизм использует систему подкачки виртуальной памяти OS для 'map' вашего буфера непосредственно на диск. OS будет управлять перемещением байтов на / из диска и памяти автоматически, очень быстро, и вам не придется беспокоиться об изменении параметров виртуальной машины. Это также позволит вам воспользоваться улучшенной производительностью NIO по сравнению с традиционной java потоковой i/o, без каких-либо странных хаков.

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

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

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


  Сведения об ответе

appple

23:38, 14th August, 2020

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

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

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


  Сведения об ответе

baggs

15:57, 28th August, 2020

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


  Сведения об ответе

screen

22:25, 19th August, 2020

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


  Сведения об ответе

qwerty101

07:23, 9th August, 2020

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

Есть ошибка в GC в каком-то солнце JVMs. Нехватка прямой памяти не вызовет GC в основной куче, но прямая память будет закреплена мусором direct ByteBuffers в основной куче. Если основная куча в основном пуста, то они долго не собираются.

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться