为了账号安全,请及时绑定邮箱和手机立即绑定

为什么使用 Image.IO malloc 的代码会占用这么多内存

为什么使用 Image.IO malloc 的代码会占用这么多内存

温温酱 2021-10-13 12:46:14
我写了一个代码来检查是否ImageIO.read会占用太多内存然后导致内存使用率高。(之前有一个生产问题)    import javax.imageio.ImageIO;    import java.awt.image.BufferedImage;    import java.io.File;    import java.io.IOException;    public class ImageIOTest2 {        public static void main(String[] args) {                for (int i = 0; i < 20; i++) {                    BufferedImage image;                    try {                        image = ImageIO.read(new File("test.jpg"));                        System.out.println(image);                        Thread.sleep(100);                    } catch (IOException) {                        e.printStackTrace();                    }                }        }    }test.jpg 大约 4.3MB(我猜可能额外的内存 4.3 * 20 *(3 或 4)不包括 JVM)。我jemalloc用来跟踪内存分配错误。LD_PRELOAD=/usr/local/jemalloc/lib/libjemalloc.so MALLOC_CONF=prof:true,lg_prof_sample:17,lg_prof_interval:25,prof_prefix:/root/output/je java -Xmx64m -Xms64m -XX:NativeMemoryTracking=summary ImageIOTest2htop 中的 RSS 大约为 160M,我打印了 NMT:Native Memory Tracking:Total: reserved=1377MB, committed=109MB-                 Java Heap (reserved=64MB, committed=64MB)                            (mmap: reserved=64MB, committed=64MB)-                     Class (reserved=1037MB, committed=10MB)                            (classes #827)                            (malloc=5MB #716)                            (mmap: reserved=1032MB, committed=5MB)-                    Thread (reserved=16MB, committed=16MB)                            (thread #17)                            (stack: reserved=16MB, committed=16MB)-                      Code (reserved=244MB, committed=3MB)                            (mmap: reserved=244MB, committed=2MB)提交的大小约为 109MB。但是来自jeprof的总内存是1055.7M:如果我在代码中什么都不做,就打印一些东西。它将 malloc 200MB。(在注释掉 ImageIO 和相同选项之前使用代码)。因此,将 4.3MB 的 jpeg 读取 20 次几乎需要 800MB。(Ps:只需使用 Files.readAllBytes 读取 jpeg 文件,只需使用相同的选项 malloc 256MB)这是正常的吗?以及如何优化内存使用ImageIO?
查看完整描述

2 回答

?
繁花如伊

TA贡献2012条经验 获得超12个赞

听起来刚刚好?让我们只计算字节数并记住垃圾收集是递增的,而不是立即进行的。

循环使用的绝对最小内存数量将是:

图像宽度 * 图像高度 * 3(每个 RGB 的字节数;实际上更可能是 4)* 20 = MEMORY。

上面的数字不依赖于技术。这只是处理的数据量。在 Java 中,只要有空闲内存可用(没有办法立即释放对象),这些内存就会累积。

既然你声称你的系统需要 800 MB,那么,向后工作,我想:

宽度 * 高度 = 800 000 000 / 20 / 4 = 40 000 000 / 4 = 10 000 000。

这一切都意味着,如果您的源图像大约为 3500 x 2500 像素,那么您的代码预计将使用 800 MB。解决它的唯一方法是在丢弃每个图像后以某种方式调用 GC。例如,通过简单地限制可用内存量。


查看完整回答
反对 回复 2021-10-13
  • 2 回答
  • 0 关注
  • 405 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信