在文章 JVM 源码解读之 CMS GC 触发条件 中分析了 CMS GC 触发的五类情况,并且提到 CMS GC 分为 foreground collector 和 background collector。 不管是 foreground collector 还是 background collector 使用的都是 mark-sweep 算法,分阶段进行标记清理,优点很明显-低延时,但最大的缺点是存在碎片,内存空间利用率低。因此,CMS 为了解决这个问题,在每次进行 foreground collector 之前,判断是否需要进行一次压缩式 GC。
CMS GC
经常有同学会问,为啥我的应用 Old Gen 的使用占比没达到 CMSInitiatingOccupancyFraction 参数配置的阈值,就触发了 CMS GC,表示很莫名奇妙,不知道问题出在哪?
前几天这篇《一个 JVM 参数引发的频繁 CMS GC》文章发出之后,反应比较激烈,因为这可能与同学们通常 GC 优化经验相悖,通常有很多业务都通过添加 -XX:+CMSScavengeBeforeRemark 参数,来降低 CMS-remark 的时间,进而提升业务的性能以及可用性。
了解 CMS GC 的同学,一定知道 -XX:CMSScavengeBeforeRemark 参数,它是用来开启或关闭在 CMS-remark 阶段之前的清除(Young GC)尝试。
GC 优化关键是找到优化的点,如果明确 GC 过程中耗时的阶段在哪里,优化起来应该也就不难了。这篇文章主要讲述最近一次 CMS GC 优化过程,是一次分享,也是一次总结。闲话少说,我们开始吧。