好好理解一下CMS收集器

首先,CMS是使用标记-清除算法,多线程的老年代收集器
传统的Parallel Old收集器在进行full GC的时候,GC线程完全的进行一次标记-整理,此时整个GC阶段都是STW的,而且时间较长。
CMS解决的问题是让老年代获得最短的回收停顿时间,即减少Stop the world时间

下面看CMS工作流程图
CMS工作流程图

对于标记-清除算法,需要STW的只有标记阶段,工作线程一边扔垃圾,GC一边清理,会导致清除不及时而造成更多次数的full GC甚至OOM;而清除这个阶段并不需要STW,因为需要清理的对象已经确定了,只需要释放该对象,不会对当前存活的对象造成任何影响。
因此,优化的关键是标记阶段:CMS解决这个问题,采用了分段标记。
初始标记只标记直接关联GC root的对象,这样极大的缩短了初始标记时间
并发标记,对于初始标记后的所有对象,开始向下遍历,标记,此时由于GC root已经确定,GC线程已经可以和工作线程同时进行,此时已经不用STW。
但是由于并发标记阶段时间较长,在并发标记阶段还会有新的垃圾出现,这时有两种策略:
1.不去标记,等到下一次GC才去标记。这样的效果就是在并发标记和并发清理产生的垃圾只能到下一次GC去清除,在高并发下高频次GC,很容易增加更多的full GC次数甚至OOM
2.重新标记,也就是CMS使用的策略,此阶段会STW,标记新的GC root并遍历(如果此时再只初始标记,那么这问题就递归了。。。),该步骤完成时,标记阶段结束,再此标记阶段后,只有并发清理后产生的垃圾会在下次GC中清理

CMS收集器,将标记阶段分成了三部分:初始标记-并发标记-重新标记,其中在大多数情况下耗时最长的并发标记不需要STW,从而缩短了STW时间

并且,在并发清理阶段,即使是使用了重新标记,只有在并发清理阶段产生的垃圾到下一次GC去收集,也会有增加full GC和OOM的风险,CMS提供了两种策略来解决该问题:
1.预留内存,使用CMS的收集器并不是老年代满了才触发Full GC,而是在使用了一大半,默认为68%,使用-XX:CMSInitiatingOccupancyFraction可以设置该比例,如果用户线程消耗内存不是特别大,可以适当调高-XX:CMSInitiatingOccupancyFraction以降低GC次数,可以提高性能
2.备用收集器,如果即使预留的内存,也在短时间填满,将使用备用方案:Serial Old 收集器,进行收集,单线程老年代收集器,此时STW时间会很长,因此-XX:CMSInitiatingOccupancyFraction不宜设的过大
这算是CMS自身的问题,对于他处理不了的没完没了的垃圾,采用了妥协的态度,让Serial Old去面对

CMS优点:
STW时间短,停顿时间短,适合在多核心的服务器上使用,核心数越多,GC线程相对的负载就越低,对于CPU资源不敏感的服务是最优选择

CMS缺点:
1.由于GC线程和用户线程大多数情况下是并行的,所以需要额外的CPU资源,当CPU资源紧张的时候,使用CMS会加重系统负担,即使STW时间较短,程序运行速度会变慢。CMS默认启动GC线程数为(CPU数量+3)/4
2.由于CMS采用的是标记-清除算法,会导致内存碎片的产生,可以使用-XX:+UseCMSCompactAtFullCollection来设置是否在Full GC之后进行碎片整理,用-XX:CMSFullGCsBeforeCompaction来设置在执行多少次不压缩的Full GC之后,来一次带压缩的Full GC(此时会STW)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值