Java BufferedImage内存消耗

Java BufferedImage memory consumption

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

java.lang.OutOfMemoryError: Java heap space

以下行会发生这种情况:

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

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

1
2
3
4
5
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时会消耗太多内存? 我们可以做些什么来减少这种情况?


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

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

在没有任何信息的情况下,总堆的大小,正在使用的GC(以及该使用的VM)的变量太多,无法使罪魁祸首。

编辑:找出使用了哪个GC(G1上的Java 7(JDK 7)垃圾收集和文档),并了解了它的特定优缺点-特别是它在堆压缩方面提供了哪些功能以及生成的代数默认。那将是要使用的参数。运行带有GC消息的应用程序也可以洞悉发生了什么。

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