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

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


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

即使没有立即使用,整个堆的地址空间也会在启动时保留。 如果它不能为您传递的-Xmx的值保留足够大的连续地址空间块,则它将无法启动。 这就是为什么在32位Windows上分配大于1.4GB的堆是很困难的 - 因为很难找到这种大小或更大的连续地址空间,因为某些DLL喜欢在某些地方加载,分割地址空间。 因为地址空间非常多,所以当你使用64位时,这并不是一个问题。

这几乎肯定是出于性能原因。 我找不到详细说明这一点的了不起的链接,但是这里有一个来自Peter Kessler的非常好的引用(完整链接 - 请务必阅读注释),我在搜索时发现了这一点。 我相信他在Sun的JVM上工作。

我们需要一个连续的堆内存区域的原因是,我们有一堆边数据结构,它们是从堆的开始处按(缩放)偏移量进行索引的。 例如,我们用一个“卡标记数组”来跟踪对象引用更新,每个512字节的堆有一个字节。 当我们在堆中存储参考时,我们必须标记卡标记数组中的相应字节。 我们右移商店的目的地址并使用它来索引卡片标记数组。 有趣的寻址算术游戏,你不能在Java中做到,你必须:(以:-)来玩C ++。

这是在2004年 - 我不确定自那时以来发生了什么变化,但我确信它仍然成立。 如果使用像Process Explorer这样的工具,则可以看到Java应用程序的虚拟大小(添加虚拟大小和专用大小内存列)包括从启动点起的总堆大小(加上其他所需空间,无疑) ,尽管进程所使用的内存将不会在堆的开始填满之前。


从历史上看,这种限制有一个原因,那就是不允许Applets在浏览器中吃掉所有用户的内存。 从来没有这种限制的微软VM实际上允许这样做,这可能导致对用户计算机的某种拒绝服务攻击。 仅在一年前,Sun在1.6.0 Update 10 VM中引入了一种让applet指定他们需要多少内存(限于物理内存的某个固定份额)的方法,而不是在计算机上始终将其限制为64MB有8GB或更多的可用。

现在,随着JVM的发展,当虚拟机不在浏览器中运行时,本应该有可能摆脱这种限制,但即使已经有大量的错误报告被提交给最终用户,但Sun显然从未认为它是如此高优先级的问题允许堆增长。


我认为这个简短而不切实际的答案是因为Sun没有发现开发它的时间和成本是值得的。

对于这种功能,最引人注目的用例是桌面,IMO和Java,在启动JVM的机制方面一直是桌面上的灾难。 我怀疑那些最关心这些问题的人倾向于将重点放在服务器端,并查看最好留给本地包装的其他细节。 这是一个不幸的决定,但它应该是决定应用程序的正确平台时的决定点之一。

链接地址: http://www.djcxy.com/p/19837.html

上一篇: Why is the maximum size of the Java heap fixed?

下一篇: Possible Memory leak in Number of Loaded classes in Java Application