Java堆行为

9

假设有以下的Java内存配置

 -Xmx2048m -Xms512m

当内存使用量超过512m时,虚拟机会有什么行为?它是否遵循特定算法?例如,它是否直接达到最大值,是否加倍,是否按增量递增,或者只在需要内存时分配?这是一个多么昂贵的操作?
我特别关注Oracle/Sun JVM 1.6版本。我认为这应该在Oracle网站上有记录,但我找不到。

它绝对不会直接达到最大值。 - Dave Newton
你正在定义最小值 + 最大值。它将至少为 512mb,但上限为 2048mb。 - adrian
据我所知,JVM在启动时分配了最小的内存值 - 因此,在启动时,它从主机操作系统消耗512m以供自己使用。我不明白的是,当它需要超过512m时,它会占用多少内存,以及如何占用?例如 - JVM需要750mb - 它会精确地消耗750mb,还是增长到1024mb?或者遵循其他行为? - Ren
3个回答

6
垃圾收集器的工作是决定何时需要调整大小,因此它由GC参数“MinFreeHeapRatio”确定。如果GC需要更多空间,则会增长到可用该值指定的堆百分比的大小。

现代平台上的典型值约为40,因此如果您从512MB开始,并且剩余不到40%的空间,表示超过了308MB左右,它将增加到再次有40%的空闲空间。例如,收集后仍然有400MB的活动对象,则堆将增加到约667MB。 (是的,它被命名为“ratio”,但需要一个%值作为参数...我也不知道!)

请注意,这有点不精确,垃圾收集器是“分代”的,实际上可以调整单个代的大小,但它还具有强制性的代大小之间的比率,如果您的对象在大致估计的长寿和短寿之间分布,则对于概略计算而言效果相当好。

这适用于Java 6中的默认值。如果您使用自定义垃圾收集器配置,则可能会有所不同。您可以在此处阅读有关此事的更多信息:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#generation_sizing.total_heap

(该操作的“成本”取决于操作系统和其他正在进行的操作。如果系统负载过重,操作系统必须进行一些交换以为您创建一个连续的内存块,则可能非常昂贵!)


2
使用-verbose:gc和/或-XX:+PrintGCDetails选项,可以给您提供许多更详细的细节。
下面是打开-verbose:gc选项的示例输出:
[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]

上述内容的解释来自官方文件
这里我们看到两个小的集合,后面跟着一个大的集合。箭头前后的数字(例如第一行中的325407K->83000K)分别表示垃圾回收前和回收后存活对象的大小总和。在小型集合之后,大小包括一些垃圾对象(不再存活),但不能被回收。这些对象要么包含在老年代中,要么从老年代或永久代引用。
括号中的下一个数字(例如第一行中的(776768K))是堆的承诺大小:可用于Java对象而无需从操作系统请求更多内存的空间量。请注意,此数字不包括其中一个幸存者空间,因为任何时候只能使用一个空间,并且还不包括持有虚拟机使用的元数据的永久代。
行末的最后一项(例如0.2300771秒)表示执行集合所需的时间;在本例中约为四分之一秒。
第三行的大型集合格式类似。
以这种方式运行应用程序,同时更新最小和最大堆大小,可以很好地了解虚拟机的堆分配和垃圾回收模式。

0

需要注意的是,JVM在初始化时虚拟保留最大地址空间,但不分配物理内存。通常,JVM会将空间分配到旧代和新生代中。在新生代中有中间空间。调用的新对象包含在新生代中。

当中间空间填满时,会调用GC,将引用对象移动到称为Survivor Space的新生代段中的一个中间空间。GC可能会遵循“停止世界”保存线程状态算法或进程继续运行的算法。

当Survivor空间填满时,JVM会调用完整的GC。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接