CMS收集器相关,学习后感

CMS设计的目的是尽可能的降低STW时间,但是CMS有很多问题,比如用标记清除算法,会产生很多的内存碎片,比如为了减少STW时间,采用的并发标记和并发清除,会在每次GC产生一些不可清理的内存,加上之前内存碎片,给人的感觉千疮百孔,于是就有很多针对这些问题而生的jvm参数。CMS在jdk9已经标位Deprecate,不推荐使用了。

CMS是一个老年代的收集器,经常配合使用的是ParNew,在JDK9之前还可以和Serial一起使用,但是JDK9之后就不能一起用了,别问我为啥,我也不知道。

CMS面试最常见的问题是标记清除的四个步骤是什么。

1.初始标记,(STW)(只扫描GCroot直接对应的对象)

2.并发标记,

3.重新标记,(STW)(遍历整个GCroot)

4.并发清除,

对应gc日志里,这四个步骤还会分为具体的7个步骤,并发标记之后还会有CMS-concurrent-preclean/Rescan (parallel) 和CMS-concurrent-abortable-preclean,

CMS-concurrent-preclean/Rescan (parallel) 并发预清理阶段,也是一个并发执行的阶段。在本阶段,会查找前一阶段执行过程中,从新生代晋升或新分配或被更新的对象。通过并发地重新扫描这些对象,预清理阶段可以减少下一个stop-the-world 重新标记阶段的工作量。

CMS-concurrent-abortable-preclean 并发可中止的预清理阶段。这个阶段其实跟上一个阶段做的东西一样,也是为了减少下一个STW重新标记阶段的工作量。增加这一阶段是为了让我们可以控制这个阶段的结束时机,比如扫描多长时间(默认5秒)或者Eden区使用占比达到期望比例(默认50%)就结束本阶段。

最后还会有一个重置的步骤。

最耗时的两个步骤是并发标记和并发清除,因为系统会分出部分线程给用户线程,部分线程分给收集器。这个公式默认是回收线程数=(CPU核心数+3)/4,也就是说当核心数特别大的时候只会分出1/4的线程来进行GC,就会特别的慢,而核心数特别少的时候,回收线程数就会占据大量核心,导致用户线程变得特别慢。

-XX:+UseCMSInitiatingOccupancyOnly

-XX:CMSInitiatingOccupancyFraction=70  

由于上文说的,并发清除在清除时,用户线程还在进行,会产生新的对象,所以很有可能在并发清除结束之前,内存就已经溢出了,所以上边这两个参数是应付这件事的,第一个参数描述是如果不开启,CMS第一次GC会按照第二个参数的值进行,之后则自己评估,而下边这个值是当内存占比达到70%这个阈值的时候则会开始CMS的GC过程,这个值过小会导致频繁GC,过大可能会导致内存溢出,这种情况出现的时候CMS则会转为SerialOld来执行GC,

-XX:+UseCMSCompactAtFullCollection

-XX:CMSFullGCsBeforeCompaction=10

上边这两个参数也是一起使用的,上边这个参数开启了,下边才有用,大概意思是在执行10次GC后会在下次gc之前整理空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值