我正在开发一个基于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:415) at
java.awt.image.Raster.createWritableRaster(Raster.java:944) at
javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073) at
javax.imageio.ImageReader.getDestination(ImageReader.java:2896) at
com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:998) at
com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966)
答案 0 :(得分:0)
解码后的图像数据(比JPG / PNG格式的压缩图像数据大得多)必须在显示时保存在某处,而某处就是堆。
如果你的意思是想要为不再显示的图像释放内存(例如,有人滚过它们),你必须确保它们不能通过绘画调用来呈现(例如,它们在屏幕外),然后您不仅需要处理图像本身,还要确保JLabel丢失了它对图像的引用,以便GC可以收集它 - dispose只是一个清除所使用的本机内存资源的提示。图像,最终你需要BufferedImage资源本身GC&#39; ed,这意味着引用它的任何对象都需要删除它的参考。
这意味着您可能需要一个足够聪明的自定义组件来使其无效。滚动屏幕时处理图像参考,然后再次显示时再次加载图像参考。
开箱即用Swing不会为你做这件事 - 你需要在这里发挥创意(我的意思是没有任何工作,它会赢得自动做到这一点......您可以使用componentListener并在可见性事件期间执行创造性的事情)