差异似乎是由垃圾收集器的幸存者空间的大小引起的。
如docs中
-Xmx所述,该标志控制内存分配池的最大大小。内存分配池的堆部分分为Eden,Survivor和Tenured空间。正如描述的这个答案,有两个幸存者的区域,只有其中之一是可在任何给定时间点要hold住对象。因此,如报告的那样,可用于分配对象的总表观空间必须从总堆内存池中减去幸存者空间之一的大小。
Runtime.maxMemory()
您可以使用
MemoryMXBean和
MemoryPoolMXBean类来获取有关内存分配的更多信息。这是我编写的一个简单程序:
import java.lang.management.ManagementFactory;import java.lang.management.MemoryMXBean;import java.lang.management.MemoryPoolMXBean;public class MemTest { static String mb (long s) { return String.format("%d (%.2f M)", s, (double)s / (1024 * 1024)); } public static void main(String[] args) { System.out.println("Runtime max: " + mb(Runtime.getRuntime().maxMemory())); MemoryMXBean m = ManagementFactory.getMemoryMXBean(); System.out.println("Non-heap: " + mb(m.getNonHeapMemoryUsage().getMax())); System.out.println("Heap: " + mb(m.getHeapMemoryUsage().getMax())); for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { System.out.println("Pool: " + mp.getName() + " (type " + mp.getType() + ")" + " = " + mb(mp.getUsage().getMax())); } }}在OpenJDK 7上,此输出
java -Xmx1024m MemTest为:
Runtime max: 1037959168 (989.88 M)Non-heap: 224395264 (214.00 M)Heap: 1037959168 (989.88 M)Pool: Code Cache (type Non-heap memory) = 50331648 (48.00 M)Pool: Eden Space (type Heap memory) = 286326784 (273.06 M)Pool: Survivor Space (type Heap memory) = 35782656 (34.13 M)Pool: Tenured Gen (type Heap memory) = 715849728 (682.69 M)Pool: Perm Gen (type Non-heap memory) = 174063616 (166.00 M)
请注意,Eden + 2 * Survivor + Tenured = 1024M,这恰好是命令行上请求的堆空间量。非常感谢@ Absurd-
Mind指出这一点。
您在不同的JVM之间观察到的差异很可能是由于选择不同版本的默认相对大小的启发式方法不同。如本文所述(适用于Java
6,无法找到更新的版本),可以使用
-XX:NewRatio和
-XX:SurvivorRatio标志来显式控制这些设置。因此,运行命令:
java -Xmx1024m -XX:NewRatio=3 -XX:SurvivorRatio=6
您要告诉JVM:
Young:Tenured = (Eden + 2*Survivor):Tenured = 1:3 = 256m:768mSurvivor:Eden = 1:6 = 32m:192m
因此,使用这些参数,请求的
-Xmx值与报告的可用内存之间的差
Runtime.maxMemory()应为32m,可使用上述程序进行验证。现在,您应该能够准确地预测
Runtime给定的命令行参数集报告的可用内存,这是您真正想要的,对吧?



