2014-09-25 2 views
0

Я занимаюсь разработкой приложения на базе Java. Здесь моя работа - поместить изображение в JLabel. Если я загружаю более 60 изображений в метки, тогда java показывает «Ошибка пространства кучи» (см. Ниже).Ошибка буфера памяти BufferdImage

Я не хочу увеличивать размер пространства кучи JDK. Я просто хочу освободить память после показа изображения в JLabel. Я использовал flush() для BufferedImage: он не очищает память.

Вот мой код

public static void setImageInLabelFromBufferedImage(JLabel label, int commonWidth, int maxImageHeight, BufferedImage img) { 
    try { 

     if (img.getWidth() < commonWidth && img.getHeight() < maxImageHeight) { 
      **img = Scalr.resize(img, Scalr.Mode.AUTOMATIC, img.getWidth(), img.getHeight(), Scalr.OP_ANTIALIAS);** 
     } else { 
      if (img.getWidth() > img.getHeight()) { 
       if (img.getWidth() > commonWidth) { 
        img = Scalr.resize(img, Scalr.Mode.FIT_TO_WIDTH, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
       } 
      } else if (img.getHeight() > img.getWidth()) { 
       if (img.getHeight() > maxImageHeight) { 
        img = Scalr.resize(img, Scalr.Mode.FIT_TO_HEIGHT, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
       } 
      } else { 
       img = Scalr.resize(img, Scalr.Mode.FIT_EXACT, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
      } 
     } 

     //BufferedImage resizedImage = Scalr.resize(img, Scalr.Mode.AUTOMATIC, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
     label.setIcon(new ImageIcon(img)); 
     label.revalidate(); 
     img.flush(); 
     img = null; 
     Runtime.getRuntime().gc(); 

    } catch (Exception e) { 
     log.error("setImageInLabelFromBufferedImage==>" + e.getMessage()); 
    } 

Трассировка стека:

java.lang.OutOfMemoryError: Java heap space at 
java.awt.image.DataBufferByte.<init>(DataBufferByte.java:92) at 
java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:4‌​15) at 
java.awt.image.Raster.createWritableRaster(Raster.java:944) at 
javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:107‌​3) at 
javax.imageio.ImageReader.getDestination(ImageReader.java:2896) at 
com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:9‌​98) at 
com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966) 
+0

возможно добавить полное сообщение об ошибке в дополнение к коду – Chris

+0

java.lang.OutOfMemoryError: Java пространство кучи \t в java.awt.image.DataBufferByte. (DataBufferByte.java:92) \t на java.awt.image.ComponentSampleModel.createDataBuffer (ComponentSampleModel.java:415) \t на java.awt.image.Raster.createWritableRaster (Raster.java:944) \t в javax .imageio.ImageTypeSpecifier.createBufferedImage (ImageTypeSpecifier.java:1073) \t на javax.imageio.ImageReader.getDestination (ImageReader.java:2896) \t в com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal (JPEGImageReader.java : 998) \t at com.sun.imageio.plugins.jpeg.JPEGImageReader.read (JPEGImageReader.java:966) –

+0

Ваш 'JLabel' с' ImageIcon' будет удерживать ссылку 'img', даже если вы делаете null e - локально. Это потребует данных изображения снова для каждой перерисовки. 'flush()' in the BufferedImage' не освобождает кучную память, поэтому это не хорошо. Также JVM должен сделать GC, прежде чем сдаваться и бросать OOME, поэтому нет необходимости запрашивать явный GC. Мне кажется, вам нужно либо избавиться от некоторых 'JLabel' с 'Icon', либо просто увеличить размер кучи JVM. – haraldK

ответ

0

данные декодированного изображения (гораздо больше, чем сжатых данных изображения в формате JPG/PNG) должен быть проведен где-то, когда и что где-то куча.

Если вы хотите освободить память для изображений, которые больше не отображаются (например, кто-то прокрутил их мимо), вам необходимо убедиться, что они не могут быть отображены вызовом краски (например, они выключены) и то вам нужно не только удалять изображение самостоятельно, но и убеждаться, что JLabel теряет ссылку на изображение, поэтому GC может его собрать - dispose - это всего лишь намек на очистку ресурсов собственной памяти, используемых ими, в конечном итоге вы 'd нужен сам ресурс BufferedImage GC'ed, что означает, что любой объект, ссылающийся на него, должен будет отбросить его ссылку.

Это означает, что вам, вероятно, нужен специальный компонент, достаточно умный, чтобы нуль & удалил ссылку на изображение при прокрутке экрана, а затем снова загрузите его, когда он снова станет видимым.

Из коробки Swing не собирается делать это за вас - вам нужно будет проявить творческий подход (я имею в виду, что без какой-либо работы это не будет делать это автоматически ... вы, вероятно, можете использовать componentListener и делать творческие вещи во время видимости событий)

+0

благодарит Riyad, если я использую Jpanel, это также вызывает ошибку OOME, но после этого помогает для 150 + imges .. –

Смежные вопросы