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

Java 为什么代码使用Image.IO mallocs会占用这么多内存,java,Java,我写了一个代码来检查ImageIO.read是否会占用大量内存,然后导致内存使用率高。(以前有生产问题) 提交的内存约为109MB 但jeprof的总内存为105570万: 如果我在代码中什么都不做,就打印一些东西。 它将为200 MB。(在注释掉ImageIO和相同选项之前使用代码)。 因此,将4.3MB jpeg文件读取20次几乎可以达到800MB。 (Ps:只需使用Files.readAllBytes读取jpeg文件,使用相同的选项仅需malloc 256MB) 这正常吗?如何使用Ima

我写了一个代码来检查
ImageIO.read
是否会占用大量内存,然后导致内存使用率高。(以前有生产问题)

提交的内存约为109MB

但jeprof的总内存为105570万:

如果我在代码中什么都不做,就打印一些东西。
它将为200 MB。(在注释掉ImageIO和相同选项之前使用代码)。
因此,将4.3MB jpeg文件读取20次几乎可以达到800MB。
(Ps:只需使用Files.readAllBytes读取jpeg文件,使用相同的选项仅需malloc 256MB)


这正常吗?如何使用
ImageIO
优化内存?

听起来很不错吧?让我们只计算字节数,记住垃圾收集是递增的,而不是瞬间的

循环使用的绝对最小内存数为:

图像宽度*图像高度*3(每RGB字节;实际上更可能是4)*20=内存

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

既然您声称您的系统需要800 MB,那么,如果反向工作,我想:

宽度*高度=8000000/20/4=4000000/4=10000


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

我在使用
ImageIO.read()
时遇到了同样的问题。这导致生产服务器上的物理内存使用量增加,操作系统杀死了该服务器上运行的3到4个tomcat实例


解决方案:使用apache commons imaging读取图像大小。

是压缩的(实际上是压缩方法),最确定的是Java保存图像时没有压缩,即每个像素。。。因此,像素计数很重要,而不是磁盘空间来确定使用了多少内存-相关:jeprof-显示77.9%的内存(约770 mb)用于解码图像像素映射。也就是说,像素颜色组件数组(每像素4字节),它是int类型的数组。@CarlosHeuberger thx~@VictorGubin,因为堆没有使用额外的内存(大小固定)。那么本机库使用了大量内存?无论如何,thx~据我所知,BuffereImage默认光栅可以直接在java 1.4中为图像pixmap分配内存。在handles模式下,它应该是对默认系统VirtualAlloc/mmap等的调用。我认为它不是GC。因为堆大小是固定的,这个额外的内存是本机内存malloc,看起来像本机lib使用了这么多?坦率地说,我仍然不太理解这个问题:您描述的一切都是100%预期的:处理800 MB的数据需要800 MB的内存。你期待什么?你的问题是什么?我的意思是800M不是用在head中,而是用在堆外(不是直接内存,而是本机内存)。GC不会在这些区域发生。我的问题是如何优化内存(可能会更改一些本机库,例如使用jemalloc来代替原始malloc)。:)要么我不明白这个问题,要么你想得太多,想找一个没有问题的问题。本机内存的GC是由Java对象的GC驱动的——如果内存是本机内存还是非本机内存,则差别不大。默认情况下,JVM通过更大的内存使用率而不是更频繁的收集来优化—如果您不喜欢,您可能希望在丢弃每个映像后调用GC。您还可以尝试在使用图像后调用flush(这可能会更快地回收一些本机资源)。这只可能会影响你的微基准-在现实世界中,800MB是800MB。这是一个生产问题。我发现GC或FGC没有立即释放内存(我使用jcmd手动释放),但过了一段时间(可能有一天晚上,这真的很奇怪)。代码读取图像并行(我的同事已将其更改为使用工作队列)。我想找到一些方法来减少读取映像时本机内存的使用(就像我之前说过的,更改本机映像库)。很抱歉没有说清楚,谢谢您的帮助~:)
    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();
                    }
                }
        }
    }
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)

-                        GC (reserved=8MB, committed=8MB)
                            (malloc=6MB #118)
                            (mmap: reserved=2MB, committed=2MB)

-                  Internal (reserved=5MB, committed=5MB)
                            (malloc=5MB #2080)

-                    Symbol (reserved=2MB, committed=2MB)
                            (malloc=1MB #200)
                            (arena=1MB #1)