我们的应用程序生成图像。 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
时为什么会消耗这么多内存?我们可以做些什么来减少这种情况?
答案 0 :(得分:2)
在多线程环境中询问运行时的可用内存量并不可靠,因为在测量之后内存可能会被另一个线程用完。此外,您正在使用maxMemory - usedMemory
,这不是可用内存量,而是VM 认为最多可以提供的内容 - 可能是主机系统无法满足请求更多内存,而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调整主题的文章。