Java BufferedImage内存消耗

Tom*_*Tom 6 java memory garbage-collection bufferedimage

我们的应用生成图像.消耗的内存会BufferedImage产生内存不足异常:

java.lang.OutOfMemoryError:Java堆空间

这发生在以下行:

BufferedImage result = new BufferedImage(2540, 2028, BufferedImage.TYPE_INT_ARGB);
Run Code Online (Sandbox Code Playgroud)

在此指令之前检查空闲内存时,它显示我有108MB可用内存.我用来检查内存的方法是:

Runtime rt = Runtime.getRuntime();
rt.gc();
long maxMemory = rt.maxMemory();
long usedMemory = rt.totalMemory() - rt.freeMemory();
long freeMem = maxMemory - usedMemory;
Run Code Online (Sandbox Code Playgroud)

我们不明白它如何BufferedImage消耗超过100MB的内存.它应该使用2540*2028*4字节,大约20 MB.

创建时为什么会消耗这么多内存BufferedImage?我们可以做些什么来减少这种情况?

Dur*_*dal 2

在多线程环境中,向运行时询问可用内存量并不真正可靠,因为在测量后内存可能会被另一个线程用完。另外,您使用的maxMemory - usedMemory不是可用内存量,而是虚拟机认为它最多可以提供的内存量 - 可能主机系统无法满足对更多内存的请求,而虚拟机仍然相信它可以扩大堆。

也完全有可能您的虚拟机有 108 MB 可用空间,但一个块中没有 20MB 可用。您尝试创建的 BufferedImage 类型最终由 int[] 数组支持,该数组必须分配为连续的内存块。这意味着如果堆上没有连续的 20MB 块可用,则无论总可用内存有多少,您都会收到 OutOfMemoryError。由于所使用的垃圾收集器,情况变得更加复杂——每个 GC 都有不同的内存分配策略;堆的相当大一部分可以留出用于线程本地内存分配。

在没有任何信息的情况下,堆总共有多大、您正在使用哪个 GC(以及哪个 VM),有太多变量无法指责罪魁祸首。


编辑:找出使用了哪种 GC(Java 7 (JDK 7) 垃圾收集和 G1 上的文档),并浏览一下它的具体优缺点 - 特别是它在堆压缩方面提供的功能以及它的代数有多大默认。这就是要使用的参数。在 GC 消息打开的情况下运行应用程序也可以提供对正在发生的情况的洞察。

考虑到你的堆大小只有 900MB,100MB 空闲意味着你已经接近极限了 -我的第一个解决方法是简单地为 VM 分配一个更大的堆,比如说 2GB。如果您需要节省内存,您唯一的选择是调整 GC 参数(可能选择另一个 GC) - 说实话我对此没有经验。不过,有很多关于 GC 调优主题的文章。