Java BufferedImage 内存消耗

Posted

技术标签:

【中文标题】Java BufferedImage 内存消耗【英文标题】:Java BufferedImage memory consumption 【发布时间】:2015-02-10 19:40:40 【问题描述】:

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

java.lang.OutOfMemoryError: Java 堆空间

这发生在以下行:

BufferedImage result = new BufferedImage(2540, 2028, BufferedImage.TYPE_INT_ARGB);

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

Runtime rt = Runtime.getRuntime();
rt.gc();
long maxMemory = rt.maxMemory();
long usedMemory = rt.totalMemory() - rt.freeMemory();
long freeMem = maxMemory - usedMemory;

我们不明白BufferedImage 怎么会消耗超过 100MB 的内存。它应该使用 2540 * 2028 * 4 字节,即 ~20 MB。

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

【问题讨论】:

请不要在问题中添加谢谢,我很感激您的 cmets 或类似的行,它们只是噪音。 感谢所有编辑人员;如果有人对此有所暗示,将对我(可能还有其他人)有更多帮助。谢谢! 【参考方案1】:

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

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

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


编辑:找出使用了哪个 GC (Java 7 (JDK 7) garbage collection and documentation on G1) 并了解它的具体优缺点 - 特别是它在堆压缩方面提供的功能以及默认情况下它的代数有多大。那将是要玩的参数。在 GC 消息打开的情况下运行应用程序还可以提供对正在发生的事情的洞察。

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

【讨论】:

谢谢。澄清一些元素:我正在使用 Oracle JRE 7 默认垃圾收集器。系统有 8GB 的​​ RAM,有很多空的,JRE 启动时有 900MB 的堆 (-Xmx900m)。应用程序此时不是多线程的,除了 EDT 线程(Swing 应用程序),但在这个阶段它没有做任何特别的事情(没有 GUI 变化)。我希望调用 gc() 会释放一个连续的内存块,正如我在某些地方所读到的那样。 @Tom 我相信将堆填充到 90% 有点太接近了,但这只是一种直觉;我对 GC 细节没有深入的了解。

以上是关于Java BufferedImage 内存消耗的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 BufferedImage 将巨大的图像加载到 Java?

用BufferedImage加载图片

java 进程消耗内存只增不减

怎么查看java程序运行的峰值内存消耗(含虚拟机)和CPU消耗(ms)

Java程序的内存消耗问题

如何查看linux上java实例消耗内存