Java堆大小-比实际需要的要大

5

根据我的计算,下面的Java程序需要约8GB(2147483645 * 4字节)的内存:

package foo;

public class Foo {
    public static void main(String[] args) throws Exception {
        int[] arr = new int[Integer.MAX_VALUE-2];
        Thread.sleep(500000L);
    }
}

观察程序运行情况可以证明这一点:

jvisualvm memory pic

但是,除非您将最大堆设置为约12.5GB,否则程序无法启动:

$ java -Xmx12000m -cp ./ foo.Foo
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at foo.Foo.main(Foo.java:5)
$ java -Xmx12500m -cp ./ foo.Foo
//this works

我能理解需要一些灵活性,但为什么我们需要这么多呢?


2
解释一下“你的数学”。 - OneCricketeer
2
当然,你的代码肯定不止包含 int[] arr = new int[Integer.MAX_VALUE-2]; 这一行。如果不告诉我们具体情况,很难确定问题所在。 - bradimus
可能相关:https://dev59.com/fGoy5IYBdhLWcg3wo_gn - OneCricketeer
2
什么?这是一个关于Java堆排列的完全合理的问题,实际上需要比其中最大的对象占用更多的空间。 - Louis Wasserman
JVM本身需要一些自由空间来呼吸。如果你真的需要分配这么多内存,你可以尝试搜索堆外分配(例如使用ByteBuffer)。 - gusto2
bradimus:提供了完整的程序,没有其他事情发生。 cricket_007:数学基本上只是MAX_INT * 4字节每个int。 gusto2:我明白它需要一些空间来呼吸,但为什么4GB不够? - biffta
1个回答

5

这是由于MinHeapFreeRatio默认值为40%造成的。如果您想要使用更少的内存,则需要指定它: 比如5% -XX:MinHeapFreeRatio=5

此外,您需要更改分配给新生代的内存大小,因为它在内存分配中扮演着重要角色:

在总可用内存之后,影响垃圾收集性能的第二个最有影响力的因素是堆专用于年轻代的比例。

请尝试以下操作:

java -Xmx9g -XX:MinHeapFreeRatio=1 -XX:MaxNewSize=256m -cp ./ foo.Foo

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/sizing.html


很好的回答,附有支持文档! - CraigR8806

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接