为什么 Java 堆的最大大小是固定的?

2022-09-01 09:53:56

VM 启动后,无法增加 Java 堆的最大大小。这是什么技术原因?垃圾回收算法是否依赖于具有固定的内存量?还是出于安全原因,为了防止 Java 应用程序通过消耗所有可用内存来 DOS 系统上的其他应用程序?


答案 1

在 Sun 的 JVM 中,最后我知道,整个堆必须分配在一个连续的地址空间中。我想对于较大的堆值,很难在启动后添加到地址空间,同时确保它保持连续。您可能需要在启动时获得它,或者根本不需要。因此,它是固定的。

即使没有立即全部使用,整个堆的地址空间也会在启动时保留。如果它不能为您传递的 -Xmx 值保留足够大的连续地址空间块,则它将无法启动。这就是为什么很难在32位Windows上分配>1.4GB堆的原因 - 因为很难找到该大小或更大的连续地址空间,因为某些DLL喜欢在某些位置加载,从而对地址空间进行分段。当您使用64位时,这并不是一个真正的问题,因为有更多的地址空间。

这几乎可以肯定是出于性能原因。我找不到一个很棒的链接来进一步详细说明这一点,但是这是我在搜索时找到的Peter Kessler的一个很好的引用(完整链接 - 请务必阅读评论)。我相信他在Sun的JVM上工作。

我们需要堆的连续内存区域的原因是,我们有一堆侧数据结构,这些结构按堆开头的偏移量(缩放)编制索引。例如,我们使用“卡标记数组”跟踪对象引用更新,该数组每 512 个字节堆有一个字节。当我们在堆中存储引用时,我们必须在卡标记数组中标记相应的字节。我们右移存储的目标地址,并使用它来索引卡标记数组。解决您在Java中无法做到的算术游戏的乐趣(必须:-)在C++玩。

这是在2004年 - 我不确定从那以后发生了什么变化,但我非常确定它仍然适用。如果您使用像 Process Explorer 这样的工具,您可以看到 Java 应用程序的虚拟大小(添加虚拟大小和私有大小内存列)包括从启动点开始的总堆大小(毫无疑问,加上其他必需的空间),即使进程“使用”的内存在堆开始填满之前不会接近该大小...


答案 2

从历史上看,这种限制是有原因的,即不允许浏览器中的小程序占用所有用户的内存。从未有过这种限制的Microsoft VM实际上允许这样做,这可能导致对用户计算机的某种拒绝服务攻击。就在一年前,Sun 在 1.6.0 Update 10 VM 中引入了一种方法,让小程序指定他们想要的内存量(仅限于物理内存的某个固定份额),而不是总是将它们限制为 64MB,即使在具有 8GB 或更多可用空间的计算机上也是如此。

现在,由于JVM已经发展,当VM不在浏览器中运行时,应该可以摆脱这种限制,但是Sun显然从未将其视为如此高优先级的问题,即使已经提交了许多错误报告以最终允许堆增长。


推荐