我正在编写一个以ImageIcons(在JLabel中)读取和显示图像的应用程序,应用程序需要能够支持jpeg和位图。
对于jpegs我发现将文件名直接传递给ImageIcon构造函数工作正常(即使显示两个大的jpeg),但是如果我使用ImageIO.read获取图像然后将图像传递给ImageIcon构造函数,我得到读取第二个图像时使用OutOfMemoryError(Java堆空间)(使用与之前相同的图像)。
对于位图,如果我尝试通过将文件名传递给ImageIcon来读取,则不会显示任何内容,但是通过使用ImageIO.read读取图像然后在ImageIcon构造函数中使用此图像可以正常工作。
我从阅读其他论坛帖子中了解到,这两种方法对于不同格式的工作原理不同的原因在于java与bitmaps的兼容性问题,但是有一种方法可以解决我的问题,以便我可以使用没有OutOfMemoryError的位图和jpeg的方法相同吗?
(我希望尽可能避免增加堆大小!)
OutOfMemoryError由此行触发:
img = getFileContentsAsImage(file);
,方法定义是:
public static BufferedImage getFileContentsAsImage(File file) throws FileNotFoundException {
BufferedImage img = null;
try {
ImageIO.setUseCache(false);
img = ImageIO.read(file);
img.flush();
} catch (IOException ex) {
//log error
}
return img;
}
堆栈跟踪是:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
at java.awt.image.Raster.createWritableRaster(Raster.java:938)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1056)
at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:925)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1282)
at framework.FileUtils.getFileContentsAsImage(FileUtils.java:33)
答案 0 :(得分:3)
由于ImageIO.read()
返回一个非常大且未保留在堆中的未压缩BufferedImage
,因此内存不足,因为ImageIcon
引用了它。但是,Toolkit.createImage
返回的图像仍采用压缩格式(使用私有ByteArrayImageSource
类。)
您无法使用Toolkit.createImage
读取BMP(即使您可能仍然在内存中保持未压缩状态,并且您可能会再次耗尽堆空间)但您可以执行的操作是读取未压缩的图像并保存它以压缩形式的字节数组,例如
public static ImageIcon getPNGIconFromFile(File file) throws IOException {
BufferedImage bitmap = ImageIO.read(file);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ImageIO.write(bitmap, "PNG", bytes);
return new ImageIcon(bytes.toByteArray());
}
这样,唯一一次必须在内存中保存未压缩位图的时候是加载或渲染它。
答案 1 :(得分:0)
你试过这个吗?
ImageIcon im = new ImageIcon(Toolkit.getDefaultToolkit().createImage("filename"));
答案 2 :(得分:0)
可能不是你确实只是内存不足?我的意思是,如果你用-Xmx1g
?