Java ImageIO 删除镜像后不会释放内存



我有一个程序可以打开一些 8k 图像并将它们调整为 200x200 像素。 该程序运行良好,但问题是它在关闭每个图像后不会释放内存,因此它会超快地耗尽内存!(喜欢40张图片后)

我尝试使用 system.gc() 刷新并将图像设置为 null,我也无法使用 ImageReader,因为图像格式不正确,并且说不是以 0x01 0x11 和其他一些数字开头的 jpeg 图像。此外,启用禁用 ImageIO.usecatch 也无济于事。我尝试为图像使用全局变量,但它也没有帮助。

我需要在线程中运行程序,但在编辑一些图像后,即使在单个线程上,它也使用了太多内存。 我删除了我确认与问题无关的额外代码部分。

static public class ImageLoadingTask implements Callable<JPanel> {
private final URL url;
private final int i;
private final JPanel scrollPane;
ImageLoadingTask(int i, URL url, JPanel scrollPane) {
this.url = url;
this.i = i;
this.scrollPane = scrollPane;
}
@Override
public JPanel call() {
try {
BufferedImage image = ImageIO.read(url);
ImageIcon icon = new ImageIcon(setImage(image));
image.flush();
image = null;
jPanels[i] = new JPanel();
jPanels[i].setLayout(new BoxLayout(jPanels[i], 
BoxLayout.Y_AXIS));
JLabel label = new JLabel();
label.setIcon(icon);
icon = null;
jPanels[i].add(label);
String name = "date";
if (name.length() > 35) {
name = name.substring(0, 32) + "...";
}
JLabel jLabel = new JLabel(name);
jPanels[i].add(jLabel);
scrollPane.add(jPanels[i]);
latch.countDown();
return jPanels[i];
} catch (Exception ex) {
ex.printStackTrace();
latch.countDown();
demo.infoBox("Failed to open file maybe file is open?",                                                 
"Error");
return new JPanel();
}
private static Image setImage(BufferedImage source) {
int height = 150;
int width = 150;
if (source.getHeight() / height > source.getWidth() / width) {
return source.getScaledInstance(source.getWidth() * height / 
source.getHeight(), height, Image.SCALE_SMOOTH);
} else {
return source.getScaledInstance(width, source.getHeight() * width 
/ source.getWidth(), Image.SCALE_SMOOTH);
}
}

我只是使用以下代码打开图像,它解决了我的问题!

Toolkittoolkit = Toolkit.getDefaultToolkit(); Image image = toolkit.getImage(url.getPath());

我认为getScaledInstance()可能会保留对原始图像的引用,该图像用于渲染该图像的缩放版本。

您应该尝试在setImage()方法中执行的操作是创建所需缩小维度的新BufferedImage,然后使用此新BufferedImagecreateGraphics()方法将缩放的实例绘制到此新BufferedImage中。然后返回新的较小BufferedImage,而不是扩展的实例本身。

此时,您应该有一个新的小图像,该图像没有任何对原始大图像的引用,并且原始大图像将通过垃圾回收免费发布。

private static Image setImage(BufferedImage source) {
int height = 150;
int width = 150;
Image scaledImage;
if (source.getHeight() / height > source.getWidth() / width) {
width = source.getWidth() * height / source.getHeight();
scaledImage = source.getScaledInstance(width, height, Image.SCALE_SMOOTH);
} else {
height = source.getHeight() * width / source.getWidth();
scaledImage = source.getScaledInstance(width, height, Image.SCALE_SMOOTH);
}
BufferedImage result = new BufferedImage(widht, height, BufferedImage.TYPE_INT_RGB);
result.createGraphics().drawImage(scaledImage, new AffineTransform(), null);
return result;
}

最新更新