cut*_*eth 7 java memory-leaks javax.imageio
我有两个Java应用程序都使用大量内存,并且都使用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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,程序都使用大量内存.就在一堆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不会回馈它不再使用的内存空间.
同意?或者我误读了这个结果?
小智 6
我有类似的东西,当我查看分配的内存时,我看到几个大块的内存(每个约10-20 MB)将无法释放.使用VirtualVM内存转储查看它们内部,似乎它们被imageIO JpegImageReader标记为"拥有".在这种情况下,GC不会清除它们,因为它们被标记为外部GNI调用(JpegImageReader)使用.并且theJpegImageReader早已不复存在,所以他们会留在那里.
就我而言,它是随机发生的.我怀疑当有多个并行调用(来自多个线程)时,或者当ImageReader中存在内部异常时,它不会释放其内存,但不是100%肯定.(是的,我会刷新缓冲的图像,处理读取器,关闭流.似乎没有帮助).
我缺少什么?了解 Java 垃圾收集的工作原理 ;-)
内存不会立即释放,只有在垃圾收集运行后才会释放。如果您愿意,可以显式调用 GC。此外,您的操作系统也发挥了一定作用 - 例如,即使您释放了内存(用 C++ 术语来说),Unix 系统通常也不会实际释放内存。
| 归档时间: |
|
| 查看次数: |
3919 次 |
| 最近记录: |