鉴于:
static final int SIZE=2*1024*1024;
public static void main(String[] a) {
int[] i = new int[SIZE];
}
2M * 4(int的字节数)= 8Mb(对于元空间可能+ 4mb,不是吗?)
以12Mb堆大小-Xmx12m -XX:+PrintFlagsFinal
运行JVM
我变得很漂亮了
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
但是当我将堆增加到13Mb时它运行得很好。
查看-XX:+PrintFlagsFinal
的值如何计算允许在没有错误的情况下运行该代码段的确切最小最大堆阈值? (概率为99%,至少几秒没有任何错误)
$ java -version
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
答案 0 :(得分:2)
如果要分配像这样的大块原语,我会使用直接内存。 ByteBuffer.allocateDirect(SIZE * 4).asIntBuffer();
无论大小如何,这几乎都不会使用堆。
在查看所需的堆时,除非您知道这是一个问题,否则我会忽略少于几百MB的开销。 100 MB的价值约为2分钟,而且可能无法有效利用您的时间担心它。
但是,一般来说,数组中的int元素需要4个字节,但需要一些开销。
答案 1 :(得分:1)
尝试运行时对象知道,请参阅:
Runtime.getRuntime().totalMemory();
Runtime.getRuntime().maxMemory();
Runtime.getRuntime().freeMemory();
答案 2 :(得分:1)
JVM使用复制,分代收集器。一个大的对象(相对于堆大小很大)将在旧一代中直接分配,这意味着你仍然需要一些额外的空间用于年轻一代(eden + survivor 1& 2)。它们的尺寸取决于所使用的收集器和各种调节旋钮。
此外,数组不会是唯一分配的对象。只需创建一个类并运行main()
,就会引入一组最小的JRE类,例如Class
,Classloader
,String
,Thread
等。您必须在空程序上进行堆转储以评估确切加载的内容。
在实践中,如果您在计算中对JVM行为做出任何微小的错误预测,那么尝试计算绝对最小值只会产生麻烦。一种更安全的方法是在给定各种输入大小的情况下测量记忆行为,然后增加一些安全余量,并审查您的算法,以确定潜在的病理行为,其中内存消耗比一般情况更差。