java imageio内存泄漏

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%肯定.(是的,我会刷新缓冲的图像,处理读取器,关闭流.似乎没有帮助).


Joh*_*136 0

我缺少什么?了解 Java 垃圾收集的工作原理 ;-)

内存不会立即释放,只有在垃圾收集运行后才会释放。如果您愿意,可以显式调用 GC。此外,您的操作系统也发挥了一定作用 - 例如,即使您释放了内存(用 C++ 术语来说),Unix 系统通常也不会实际释放内存。