Утечка Java ByteArrayOutputStream в памяти

Я создал новый вопрос, потому что он отличается от моего предыдущего треда. Теперь я знаю, в чем проблема точнее.

Я создаю новый bytearrayoutputstream

ByteArrayOutputStream byteArray = new ByteArrayOutputStream();

Ничего особенного. Затем, когда я пишу на него изображение, вот так

ImageIO.write(image, "gif", byteArray);

память увеличивается вроде на 100 мб сначала, не в eclipse, а в "реальности". Затем он медленно увеличивается после этого каждый раз, когда я записываю новое изображение в этот поток ИЛИ в другой!!

и через некоторое время он перестает работать и как бы вылетает.

Я пытался закрыть его и все такое, сбрасывать, сбрасывать, все, но память все равно уходит. Я хочу, чтобы он ушел из памяти, когда я перестану использовать byteArray или обнулю его.

System.gc();

не поможет в этом случае.

Пожалуйста, помогите мне, и все, что вам нужно знать, я отвечу, и, пожалуйста, вернитесь и отвечу обратно :)


person Wille Sandström    schedule 14.08.2012    source источник
comment
В этом случае вам не нужно вызывать System.gc() вручную. Если вы закрыли все неиспользуемые ресурсы/потоки/и т. д., то все должно быть в порядке. Попробуйте увеличить лимит памяти Java   -  person nevets1219    schedule 14.08.2012
comment
Я согласен. Вероятно, вы делаете что-то не так в коде, который не показан.   -  person Hovercraft Full Of Eels    schedule 14.08.2012
comment
Вы не должны вызывать System.gc()... Java предоставляет автоматическую функцию gc. Просто разыменуйте переменную. Также, пожалуйста, включите больше кода   -  person Vikram    schedule 14.08.2012
comment
возможный дубликат Java записи в утечку памяти ByteArrayOutputStream   -  person Christoffer Hammarström    schedule 16.08.2012


Ответы (4)


Ваш шаблон использования должен быть таким:

while( keepRunning) {
     ByteArrayOutputStream byteArray = new ByteArrayOutputStream();   
     ImageIO.write(image, "gif", byteArray);
}

Если вы сделаете это быстрее, чем JVM сможет собрать мусор, вы в конечном итоге получите очень длинную паузу GC или исключение OutOfMemory.

person Dave    schedule 14.08.2012
comment
Неа. Не так быстро. Может быть, раз в секунду я делаю это. Но после этого закрываю. - person Wille Sandström; 14.08.2012
comment
В любом случае, я могу использовать один и тот же байтовый поток вывода и сбрасывать его каждый раз, когда я использовал его данные? - person Wille Sandström; 14.08.2012
comment
Вы сбрасываете его сейчас? Сброс не избавит от существующей выделенной памяти, но перезапишет существующий базовый буфер byte[]. - person Dave; 14.08.2012
comment
Как я могу избавиться от него тогда? - person Wille Sandström; 14.08.2012
comment
Вам нужно показать более крупный фрагмент кода, чтобы действительно понять, что вы делаете. Он должен показывать, где инициализируется ByteArrayOutputStream и где/когда он обновляется. - person Dave; 14.08.2012
comment
Я показал все. Просто вызовите эти 2 строки кода, и изображение должно загрузиться в память. - person Wille Sandström; 14.08.2012
comment
В этом случае вам следует попробовать увеличить размер кучи и посмотреть, сможет ли JVM выполнить GC до того, как ей не хватит памяти. - person Dave; 21.08.2012

Вы пробовали это:

 try{
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ImageIO.write(image, "png", baos);
  baos.flush();
  byte[] imageBytes = baos.toByteArray();
  baos.close();
}catch(Exception ex){
  System.out.println(ex.getMessage());
}
person Vikram    schedule 14.08.2012
comment
Делает то же самое. Все еще остается в памяти - person Wille Sandström; 14.08.2012

То, что вы делаете, не имеет никакого смысла. Вы берете изображение из памяти и снова помещаете его в память, на этот раз в виде массива байтов.

Вы должны поместить это изображение в файл или отправить по сети. Или, если вы хотите просто сохранить копию, скопируйте изображение (а не массив байтов!), Как я описал здесь: Ошибка при использовании Object.clone()

person mark    schedule 26.10.2012

Пожалуйста, обратитесь к похожему ответу, который я отправил на другой вопрос ByteArrayOutputStream.

В ByteArrayOutputStream нет метода, позволяющего сжимать буфер. Сброс изменяет положение в буфере.

Решение для вас состоит в том, чтобы

  1. Используйте конструктор, чтобы указать размер буфера перед использованием. Когда вы записываете большие объекты в поток, это сэкономит много памяти и предотвратит исключения OOM.
  2. Если вы хотите повторно использовать свой объект BAOS, вызовите reset. Это заставит следующую запись начаться в начале буфера.
  3. Единственный способ освободить память — удалить все ссылки на нее. В приведенном выше коде вы бы сказали byteArray=null;
person Derek Bennett    schedule 28.11.2012