【问题标题】:BufferdImage heap space errorBufferdImage 堆空间错误
【发布时间】:2014-09-25 10:05:37
【问题描述】:

我正在开发一个基于 Java 桌面的应用程序。在这里,我的工作是将图像放入JLabel。如果我将超过 60 个图像加载到标签中,那么 java 会显示“堆空间错误”(见下文。)

我不想增加 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)

【问题讨论】:

  • 除了代码之外,还可以添加完整的错误信息
  • java.lang.OutOfMemoryError:java.awt.image.DataBufferByte 处的 Java 堆空间。(DataBufferByte.java:92) 处 java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java :415) 在 java.awt.image.Raster.createWritableRaster(Raster.java:944) 在 javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073) 在 javax.imageio.ImageReader.getDestination(ImageReader.java:2896)在 com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:998) 在 com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966)
  • 您的 JLabelImageIcon 将保留 img 引用,即使您在本地执行 null 引用。每次重绘都需要图像数据。 flush()BufferedImage 不会释放堆内存,所以不好。此外,JVM 应该在放弃并抛出 OOME 之前进行一次 GC,因此无需要求显式 GC。在我看来,您需要用Icons 摆脱一些JLabels,或者只是增加JVM 堆大小。
  • 但我需要带有图标的 jlabel .. 有没有其他方法可以做到这一点?我将 JtextPane 与 html 内容一起使用。在这种情况下,问题是一样的。

标签: java out-of-memory heap-memory bufferedimage


【解决方案1】:

解码后的图像数据(比 JPG/PNG 格式的压缩图像数据大得多)在显示时必须保存在某个地方,而这个地方就是堆。

如果您的意思是要为不再显示的图像释放内存(例如有人滚动过它们),您必须确保它们不能通过绘制调用呈现(例如它们不在屏幕上),然后您不仅需要处理图像本身,还需要确保 JLabel 丢失它对图像的引用,以便 GC 可以收集它 - 处理只是清理图像使用的本机内存资源的提示,最终你' d 需要 BufferedImage 资源本身 GC'ed,这意味着任何引用它的对象都需要删除它的引用。

这意味着您可能需要一个足够聪明的自定义组件,以便在滚出屏幕时清空并处理图像引用,然后在它再次可见时再次加载它。

开箱即用的 Swing 不会为您执行此操作 - 您需要在这里发挥创意(我的意思是没有任何工作它不会自动执行此操作...您可能可以使用 componentListener并在知名度活动期间做有创意的事情)

【讨论】:

  • 感谢 Riyad,如果我使用 Jpanel,它也会导致 OOME 错误,但在它有助于 150 + 图像之后..
猜你喜欢
  • 2016-01-19
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 2016-04-10
  • 2011-10-10
  • 2014-12-28
  • 1970-01-01
相关资源
最近更新 更多