堆大小大于 -Xmx

Heap size is greater than -Xmx

我使用 -Xms256m and -Xmx256m JVM options. The GC log (using -XX:+PrintHeapAtGC) states that the heap size is 251904K (246MB), which is smaller than the minimum heap size, -Xms256m (see last line of log). However, this is because the stated heap size is the available heap size, which does not include 将初始和最大 Java 堆大小设置为 256MB。

当我手动包含不可用的from space内存时,导出的堆大小为262656K(256.5MB),略微大于最大堆大小,-Xmx(512KB):

[heap size] = [eden space size] + [from space size] + [to space size] + [OldGen size]
  262656K   =       66048K      +       10752K      +     10752K      + 175104K

为什么堆大小比最大堆大小稍大,-Xmx?

起初看起来很奇怪,但和往常一样没有魔法。找出答案的唯一方法是更深入:到openjdk sources。只需结帐并尝试 grep:grep -r "Xmx" .

会有很多测试,但它们对我们来说并不有趣。两个文件可以帮助我们:/vm/runtime/arguments.cpp 和 /vm/memory/collectorPolicy.cpp

我们来看一下arguments.cpp:只有简单的参数解析,例如对于 -Xmx256M,它将类似于 result = 256 * 1024 * 1024(我做了一些内联)。所以我们的问题没有答案。

但是这里初始化了变量MaxHeapSize,所以我们可以尝试找到它。 MaxHeapSize 的实际用法可以在我们的 /vm/memory/collectorPolicy.cpp 中找到(其中 Xmx 仅在注释中使用),其中所有堆生成大小均由某些策略选择。

如果我们跳过所有细节,我们会发现堆中的所有区域都应该对齐,并且区域的大小取决于比率参数。

生成比率的默认 JVM 参数是 -XX:NewRatio=2(年轻 gen:old 生成比例)和 -XX:SurvivorRatio=8(eden:survivor 生成比例)。但是堆大小并不总是可以被 3、9 或其他东西整除,所以应该进行一些舍入。而且,正如我之前提到的,始终应该保持一致。

所以,终于有了答案:这些大小是唯一可能满足世代比和对齐条件的大小。这些值的总和并不总是可能等于 Xmx 参数值。

如果您对细节感兴趣,可以在方法 scale_by_NewRatio_aligned 中找到四舍五入的逻辑 -XX:NewRatio here。 尝试自己找到关于 -XX:SurvivorRatio 的相同逻辑:)