CMS垃圾收集器 - 何时运行?

11

我对可能控制CMS收集器何时开始的两个参数感到困惑:

MaxHeapFreeRatio(默认为70%)

CMSInitiatingOccupancyFraction(默认超过90%)

这两个参数具体是什么意思? 收集器何时开始(标记阶段)和收集(清扫阶段)?

1个回答

13

CMSInitiatingOccupancyFraction决定了CMS何时启动(为了使此选项生效,您还必须设置-XX:+UseCMSInitiatingOccupancyOnly)。MaxHeapFreeRatio是一个用于调整分代空间大小的选项。

例如,请参见...

http://java.sun.com/docs/hotspot/gc1.4.2/faq.html

并发集合通常无法加速,但可以提前启动。 当老年代中分配空间的百分比超过阈值时,并发集合开始运行。该阈值是根据对并发收集器的一般经验计算得出的。如果正在发生全收集,则可能需要提前启动并发收集。可以使用命令行标志CMSInitiatingOccupancyFraction来设置启动收集的级别。其默认值约为68%。调整该值的命令行为 -XX:CMSInitiatingOccupancyFraction=<percent>

http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html

默认情况下,虚拟机在每次垃圾回收时会自动调整堆的大小,以尽量保持每次回收时空闲空间与存活对象的比例在特定范围内。这个目标范围通过参数-XX:MinHeapFreeRatio=<minimum>-XX:MaxHeapFreeRatio=<maximum>以百分比的形式设置,并且总大小在-Xms下限和-Xmx上限之间。

http://www.petefreitag.com/articles/gctuning/

-XX:MaxHeapFreeRatio - 当某一代中的空闲空间百分比超过此值时,该代将缩小以满足此值。默认值为70。
编辑:我运行了几个模拟实验,使用一个测试程序随机创建字节数组的映射并进行复制。我注意到:a)分数值没有被尊重 - 特别是在保守值(比如50)的情况下,CMS初始标记阶段的触发点远远超过50%的占用率,通常在70-80%左右;b)尽管如此,较小的分数值会使CMS初始阶段提前发生(程序使用了-Xmx1536m -Xmx1536m -XX:NewSize=512m -XX:+UseConcMarkSweepGc + gc logging和两个测试参数)。
我还找到了一个关于此问题的旧的错误报告:https://bugs.java.com/bugdatabase/view_bug?bug_id=6486089

5
CMSInitiatingOccupancyFraction仅在第一次回收时使用,除非设置了-XX:+UseCMSInitiatingOccupancyOnly开关。如果没有设置后者开关,则在第一次之后,通常的启发式算法(基于运行时收集的分配统计信息)将用于确定何时启动CMS垃圾回收。 - Matt
从一些观察来看,在低使用率的几个夜间小时后,它似乎直到达到90%以上才开始运行(即CMSInitiatingOccupancy)。然而,在白天它似乎不需要等待那么长时间,但会更早地进行收集。这似乎与@Matt所说的相符,但在这种情况下,我想知道“通常的启发式算法”是什么,以及和平时间有多长会使其进入休眠并等待>90%的阈值。 - Konrad Garus
1
我个人没有遇到过这个问题,但我的理解是,当你设置了XX:+UseCMSInitiatingOccupancyOnly时,JVM应该尊重CMSInitiatingOccupancyFraction中设置的值。如果你没有使用UseCMSInitiatingOccupancyOnly,那么JVM就有一些余地。 - moodywoody
启动终身集合的决定基于以往的收集时间和过去填充终身所需的时间。如果它知道完成一个周期通常需要一分钟,并且从80%到完整需要一分钟,那么它将在占用率低于80%时开始。我认为这个决定也受到终身碎片化水平的影响(因为CMS不是复制收集器,所以它会受到碎片化的影响,因此可能需要进行全STW紧凑收集)。 - Matt

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