有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

垃圾收集为什么Java堆的最大大小是固定的?

在虚拟机启动后,需要增加Java堆的最大大小。技术原因是什么?垃圾收集算法是否依赖于使用固定数量的内存?还是出于安全原因,通过消耗所有可用内存来防止Java应用程序拒绝系统上的其他应用程序


共 (5) 个答案

  1. # 1 楼答案

    来自IBM的performance tuning tips(因此可能不直接适用于Sun的VM)

    The Java heap parameters influence the behavior of garbage collection. Increasing the heap size supports more object creation. Because a large heap takes longer to fill, the application runs longer before a garbage collection occurs. However, a larger heap also takes longer to compact and causes garbage collection to take longer.

    The JVM has thresholds it uses to manage the JVM's storage. When the thresholds are reached, the garbage collector gets invoked to free up unused storage. Therefore, garbage collection can cause significant degradation of Java performance. Before changing the initial and maximum heap sizes, you should consider the following information: In the majority of cases you should set the maximum JVM heap size to value higher than the initial JVM heap size. This allows for the JVM to operate efficiently during normal, steady state periods within the confines of the initial heap but also to operate effectively during periods of high transaction volume by expanding the heap up to the maximum JVM heap size. In some rare cases where absolute optimal performance is required you might want to specify the same value for both the initial and maximum heap size. This will eliminate some overhead that occurs when the JVM needs to expand or contract the size of the JVM heap. Make sure the region is large enough to hold the specified JVM heap. Beware of making the Initial Heap Size too large. While a large heap size initially improves performance by delaying garbage collection, a large heap size ultimately affects response time when garbage collection eventually kicks in because the collection process takes more time.

    所以,我猜您不能在运行时更改该值的原因是因为它可能没有帮助:要么堆中有足够的空间,要么没有。一旦用完,就会触发GC循环。如果这还不能腾出空间,你就已经吃饱了。您需要捕获OutOfMemoryException,增加堆大小,然后重试计算,希望这次您有足够的内存

    通常,除非您需要,否则VM不会使用最大堆大小,因此,如果您认为可能需要在运行时扩展内存,可以只指定一个较大的最大堆大小

    我承认这有点不令人满意,而且似乎有点懒惰,因为我可以想象一种合理的垃圾收集策略,当GC无法释放足够的空间时,它会增加堆的大小。不过,我的想象力是否转化为高性能GC实现是另一回事;)

  2. # 2 楼答案

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

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

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

    The reason we need a contiguous memory region for the heap is that we have a bunch of side data structures that are indexed by (scaled) offsets from the start of the heap. For example, we track object reference updates with a "card mark array" that has one byte for each 512 bytes of heap. When we store a reference in the heap we have to mark the corresponding byte in the card mark array. We right shift the destination address of the store and use that to index the card mark array. Fun addressing arithmetic games you can't do in Java that you get to (have to :-) play in C++.

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

  3. # 3 楼答案

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

    现在,由于JVM已经进化,当VM不在浏览器中运行时,应该可以摆脱这个限制,但是Sun显然从未考虑过这样的高优先级问题,尽管已经提交了许多错误报告,最终允许堆增长

  4. # 4 楼答案

    我的直觉是,它与操作系统上运行的其他应用程序的内存管理有关

    例如,如果您将最大堆大小设置为机箱上的RAM量,那么实际上可以让VM决定它需要多少内存(达到此限制)。这样做的问题是,虚拟机可能会有效地削弱它正在运行的机器,因为在它决定需要进行垃圾收集之前,它将接管机器上的所有内存

    当您指定最大堆大小时,您要对VM说的是,允许您在需要开始垃圾收集之前使用此内存量。您不能拥有更多,因为如果您使用更多,则机箱上运行的其他应用程序将变慢,如果您使用的数量超过此数量,您将开始交换到磁盘

    还要注意,它们是关于内存的两个值,即“当前堆大小”和“最大堆大小”。当前堆大小是堆大小当前使用的内存量,如果需要更多内存,则可以调整堆大小,但不能将堆大小调整到最大堆大小的值以上

  5. # 5 楼答案

    我认为简短、刺耳的答案是因为Sun觉得它不值得花时间和成本来开发

    这种特性最引人注目的用例是在桌面上,IMO,而Java在启动JVM的机制上一直是桌面上的一场灾难。我怀疑那些对这些问题想得最多的人倾向于关注服务器端,并查看最好留给本机包装器的任何其他细节。这是一个不幸的决定,但在为应用程序选择合适的平台时,这应该只是决定点之一