2014-09-25 121 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 2014-09-25 10:08:15

+0

java.lang.OutOfMemoryError:在java.awt.image.DataBufferByte中的Java堆空间 \t。 (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) – 2014-09-25 10:40:31

+0

即使你没有使用'ImageIcon',你的'JLabel'也会保留在'img'引用上e本地参考。每次重绘都会再次需要图像数据。 flush()'BufferedImage'不释放堆内存,所以它不好。在放弃和抛出OOME之前,JVM也应该做GC,所以不需要明确的GC。对我来说,你需要用Icon来摆脱一些JLabel,或者只是增加JVM堆大小。 – haraldK 2014-09-26 09:35:00

回答

0

解码后的图像数据(比JPG /的PNG格式的压缩图像数据大得多)在某处时举行显示,并在某个地方是堆。

如果你的意思是你想释放不再显示图像的内存(例如某人已经滚过它们),你将不得不确保它们不能通过绘画调用渲染(例如它们不在屏幕上)并且那么你不仅需要处理图像本身,还要确保JLabel失去它对图像的引用,以便GC可以收集它 - 处理只是清理图像使用的本地内存资源的一种暗示,最终你'需要BufferedImage资源本身GC'ed,这意味着任何引用它的对象都需要删除它的引用。

这意味着您可能需要一个足够聪明的自定义组件,以便在滚动屏幕时处理图像引用,并在再次变为可见时再次将其加载。

开箱即用Swing不会为你做这件事 - 你需要在这里发挥创意(我的意思是没有任何工作,它不会自动执行此操作......你可以使用的ComponentListener并在能见度事件做创意的东西)

+0

感谢利雅得,如果我使用Jpanel,它也会导致OOME错误,但是在它帮助150 + imges后.. – 2014-10-13 12:00:35