性能问答>如何理解CMS和CMSFullGCsBeforeCompaction?>
1回复
1年前

如何理解CMS和CMSFullGCsBeforeCompaction?



关于CMSFullGCsBeforeCompaction,网上最多的一段话是:

CMSFullGCsBeforeCompaction 说的是,在上一次CMS并发GC执行过后,到底还要再执行多少次full GC才会做压缩。默认是0,也就是在默认配置下每次CMS GC顶不住了而要转入full GC的时候都会做压缩。 把CMSFullGCsBeforeCompaction配置为10,就会让上面说的第一个条件变成每隔10次真正的full GC才做一次压缩(而不是每10次CMS并发GC就做一次压缩,目前VM里没有这样的参数)。这会使full GC更少做压缩,也就更容易使CMS的old gen受碎片化问题的困扰。 本来这个参数就是用来配置降低full GC压缩的频率,以期减少某些full GC的暂停时间。CMS回退到full GC时用的算法是mark-sweep-compact,但compaction是可选的,不做的话碎片化会严重些但这次full GC的暂停时间会短些;这是个取舍。

我所知道的关于CMS,有如下几个细节:
1 CMS不是full GC,但是CMS包括两次Full GC,一次是初始标记,一次是重新标记,因为这两次导致Stop-The-world
https://www.jianshu.com/p/f77
2 CMS在concurrent mode failure之后会进行一次串行Full GC
3 CMS的并发清理阶段是清除而不是压缩

我的问题是,在jvm GC设置为CMS时
1 CMS在concurrent mode failure之后会进行一次串行Full GC是标记-压缩还是标记-清除?
2 文中的“每隔10次真正的full GC才做一次压缩”,这里说的Full GC是指上面1中的串行GC还是什么?
3 常见下面的说法,Full GC(major GC)的四个触发条件如下

调用System.gc()时,系统建议Full GC,不一定进行
年老代空间不足
元空间或者永久代空间不足
历次Minor GC后进入老年代对象的平均大小大于老年代的可用内存(分配担保机制)
因为CMS不是full GC,那么当Jvm GC设置为CMS时,上面四个触发条件导致的是CMS吗?还是full GC?

2848 阅读
请先登录,再评论

我回答一下好了,如果不对请指正。
1 CMS在concurrent mode failure之后会进行一次串行Full GC是标记-压缩还是标记-清除?
这个问题你贴出来的内容,已经帮你回答了。
每隔10次真正的full GC才做一次压缩(而不是每10次CMS并发GC就做一次压缩,目前VM里没有这样的参数)。

如果把答案说的清楚明白,那么答案是:具体取决于你的jvm参数。
默认场景下参数为:-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0。这意味着每次full gc(标记清除)后,都会压缩。那么答案就是100%都是标记-清除-压缩。如果你的CMSFullGCsBeforeCompaction设置为5,那么每6次full gc,其中才有1次是标记-清除-压缩。

2 文中的“每隔10次真正的full GC才做一次压缩”,这里说的Full GC是指上面1中的串行GC还是什么?
说的是是1的串行full gc。CMS场景下(JDK 8场景下),所有操作都是parallel(parallel指的是gc本身是多线程,concurrent指的是gc和用户工作线程同时运行,别混了)的,除了因为concurrent mode failure等原因。退化到单线程full gc。
说的再清楚明白一点,CMS只有因为concurrent mode failure等原因,退化到serial full gc的时候,才会使用单线程垃圾回收。(其实这里也是可以做成多线程的,但是当时因为人力原因没做,谷歌提了个patch,但是最后也没被合进去,阿里jdk把它合进去了,可以通过CMSParallelFullGC参数开启,但是大部分jdk都没有这个功能,所以在退化场景下,只能用单线程,也就是问题1里面的串行gc)

3 具体问题得看jvm源码,我记的不是特别清楚,以为记忆中来说,这四个全是导致串行full gc。

21年前