【发布时间】:2013-09-10 07:29:33
【问题描述】:
我有两个 Java 应用程序,它们都使用 ton 内存,并且都使用 ImageIO.write()。到目前为止,这是我发现两者之间唯一的共同点。
一个循环调整图像大小。另一个循环下载图像并将它们保存到磁盘。以下是相关代码:
1)
for(File imageFile : imageFilesList)
{
if(!stillRunning) return;
File outputFile = new File(imageFile.getAbsolutePath().replace(sourceBaseFolder.getAbsolutePath(), destinationFolder.getAbsolutePath()));
try
{
outputFile.mkdirs();
BufferedImage inputImage = ImageIO.read(imageFile);
BufferedImage resizedImage = ImageResizer.resizeImage(inputImage, maxHeight, maxWidth);
ImageIO.write(resizedImage, "jpg", outputFile);
}
catch(IOException ex)
{
userInterface.displayMessageToUser("IOException ocurred while converting an image: " + ex.getLocalizedMessage());
System.out.println(outputFile.getAbsolutePath());
ex.printStackTrace();
return;
}
imagesConverted++;
userInterface.updateTotalConvertedImages(++convertedFiles);
}
2)(在循环内)
try
{
u = new URL(urlString);
uc = u.openConnection();
uc.addRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
uc.connect();
uc.getInputStream();
in = uc.getInputStream();
BufferedImage tempImage = ImageIO.read(in);
String fileName = fn = ImageDownload.getFileName(u.getPath());
fileName = outputDirString + FILE_SEPARATOR + fileName;
while (new File(fileName).exists())
{
fileName = appendCopyIndicator(fileName);
}
ImageIO.write(tempImage, "jpg", new File(fileName));
parent.notifyOfSuccessfulDownload(fn);
in.close();
}
catch (FileNotFoundException ex)
{
parent.notifyOfFailedDownload(fn);
}
catch (IOException ex)
{
parent.handleException(ex);
}
在这两种情况下,程序都会占用大量内存。就在 RAM 的演出周围。并且当循环结束时它不会被释放。在这两种情况下,我都有一个摆动 gui 运行。当图像保存完成并且 gui 只是空闲时,程序有时仍在使用 1Gb+ 的内存。
我什至在循环后将 Swing gui 不直接使用的每个变量都设置为 null。没有效果。
我错过了什么?
提前感谢您的帮助。
更多信息: 我刚刚在我的 IDE (Netbeans) 中分析了应用程序 1。我选择了应用程序一,因为它只处理 ImageIO(而不是网络 IO),所以这是一个更受控制的实验。
当程序在做它的事情时(在循环中调整图像大小),总内存在大约 900,000,000 ~ 1,000,000,000 字节之间徘徊,而已用内存在给定的使用的总内存的大约 30% 和 50% 之间波动时刻。
花在 GC 上的时间从未超过 1%。
当实际的大小调整完成并且程序进入“空闲”状态时,发生了两件事:1) 总内存停止波动并保持在 1,044,054,016 字节的静态,2) 已用内存降至约 14,000,000 字节 ( 14 mb)。
所以,看起来 JVM 只是没有归还它不再使用的内存空间。
同意吗?还是我误读了这个结果?
【问题讨论】:
-
使用大量内存不一定是内存泄漏。它会不断增长并耗尽内存吗?是不是你的内存需求在1G左右?
-
考虑发布SSCCE;每个人都会更容易评估您遇到的问题。
-
你的意思是虚拟机不会把内存还给操作系统吗? AFAIK VM 不会那样做;一旦它向操作系统请求了内存,它就不会归还。
-
顺便说一句,你真的应该在第一个例子中调用 outputFile.close()。
-
另外,
inputFile每次循环都超出范围,因此每次循环都会收集垃圾并重新分配。我在分析测试中观察到了这一点,因为即使我在循环中批量调整 1000 多张图像的大小,java.io.File 的实时实例数也永远不会超过 90。
标签: java memory-leaks javax.imageio