【问题标题】:High ram usage when loading image with BufferedImage使用 BufferedImage 加载图像时内存使用率高
【发布时间】:2019-08-08 10:28:35
【问题描述】:

我创建了一个程序,它使用 FileDialog 加载图像、调整大小、预览给用户,并在单击按钮后将其保存到文件夹中。

我的问题是:

  1. 当我运行我的程序时 - RAM 使用量 ~50mb
  2. 加载 1mb JPG 文件 - RAM 使用量 ~93mb
  3. 保存 1mb JPG 文件 - RAM 使用 ~160mb

我希望这个程序是轻量级的,但是在 3-4 个文件之后它会占用 500mb RAM 空间。

我尝试在每次用户保存文件时使用System.gc();,但它只减少了大约 10% 的 RAM 使用量。

下面是加载和保存图片的代码,完整代码,你可以找到HERE

顺便说一句 - 为什么在加载 1mb JPG 然后将其保存到 10mb 之后?

图片加载代码:

    FileDialog imageFinder = new FileDialog((Frame)null, "Select file to open:");
            imageFinder.setFile("*.jpg; *.png; *.gif; *.jpeg");
            imageFinder.setMode(FileDialog.LOAD);
            imageFinder.setVisible(true);
            userImagePath = new File(imageFinder.getDirectory()).getAbsolutePath()+"\\"+imageFinder.getFile();

            userImagePath = userImagePath.replace("\\", "/");

图片保存代码:

 BufferedImage bimage = new BufferedImage(userImage.getWidth(null), userImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);

                    Graphics2D bGr = bimage.createGraphics();
                    bGr.drawImage(userImage, 0, 0, null);
                    bGr.dispose();

                    try {
                        BufferedImage bi = bimage;
                        File outputfile = new File("C:\\Users\\Mariola\\git\\MySQL-viwer\\MySQL viewer\\src\\database_images\\"+userBreedInfo[0]+".jpg");
                        ImageIO.write(bi, "png", outputfile);
                    } catch (IOException e1) {

                    }
            }
            System.gc()

【问题讨论】:

  • 我不推荐空的 catch 块。至少记录异常。
  • 您应该记住 jpg 是一种压缩图像格式。当它被解压缩成 BufferedImage 时,每个像素可能由 4 个整数值 (RGBA) 表示,具体取决于您的图像格式/颜色空间。这意味着一张 100x100 像素的图像占用了 40,000 个整数值。
  • ImageIO.write 很可能是这里的罪魁祸首。这不一定是泄漏,JVM 可能只是不释放资源。你可以忘记System.gc(),这只是一个建议,并不可靠,并且广泛建议不要使用。
  • @Mär - 有没有更好的方法来保存图像并在之后释放资源?
  • “我希望这个程序是轻量级的,但是在 3-4 个文件之后它会占用 500mb RAM 空间。” 然后启动有限 RAM 的 JVM! JVM 仅在需要时才会进行 GC。见What is the XY problem?

标签: java swing bufferedimage ram


【解决方案1】:

“问题”是ImageIO 类型使用大量内存。然后这个内存将不会返回给操作系统(这就是为什么即使不需要调用 System.gc() 也不会返回它)因为这就是 JVM 的工作方式。(Java 13 承诺内存将返回给操作系统?)如@Andrew Thompson 在评论部分指出,如果您想减少内存消耗,请查看 question。如果你运行它,你会看到内存限制它不会消耗太多。这实际上告诉你不要担心。 JVM 会发挥它的魔力,并根据操作系统所说的可用内存量来处理内存消耗。

如果它仍然困扰您,您可以尝试找到任何可能表现不同的 ImageIO 替代品。但在我看来,这不值得您的需求。我的意思是,您只想保存/加载图像。

另一个值得一读的问题是Why is it bad practice to call System.gc()?

【讨论】:

  • 谢谢!我会照你说的做。我将我的 VM 参数设置为 -Xmx200m 并且正如预期的那样,程序运行在 260mb 以下。我会尝试找到比ImageIO更好的解决方案。
  • 我只是希望也许有一些方法可以限制程序中的 RAM,而不是作为 JVM 起始参数:)
  • ImageIO 使用的内存并不多,而是将解码后的像素保存在内存中(就像 BufferedImage 一样)需要一定量的内存(宽度 * 高度 * bytesPerPixel 至少)。
猜你喜欢
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-03
  • 2016-05-18
相关资源
最近更新 更多