垃圾回收器之CMS

CMS是一款基于“标记-清除”算法的垃圾回收器,用于老年代的回收。

CMS的大概处理流程为:初始标记-并发标记-重新标记-并发清除。为什么需要重新标记呢,因为在并发标记阶段,用户线程和标记线程同时运行,这时会出现之前标记的对象发生了变化,需要等并发标记结束后,重新标记这一部分对象。当重新标记结束后,进行并发清除可回收对象。在初始标记和重新标记时,会导致stop the world,但这个时间远比并发标记时间短,可极大压缩停止时间。初始标记只是简单标记下GC ROOTS可达的节点,并发标记时进行GC ROOTS Tracing的过程。

CMS垃圾回收器有一部分缺陷。

1.抢占cpu资源,并发操作就需要创建线程,创建了额外的线程会抢占cpu资源。CMS的默认线程数计算公式为:(cpu数量+3)/4,当cpu数量大于4时,会创建一个线程,这时线程数量占25%,影响不大,但当数量小于4时,会基本占用50%的资源,严重影响业务线程的执行时间。虽然后来提供了i-cms垃圾回收器,在并发标记、清除阶段,试图通过交替运行用户线程,减少这种影响,但效果不明显。

2.无法处理浮动垃圾。在CMS进行并发清除阶段,用户线程也在运行,会产生新的对象,这部分称为浮动垃圾。CMS在清除时,无法处理浮动垃圾,而这部分数据需要内存空间存放,所以CMS不能等到内存空间完全占满时运行,在1.5版本时,达到68%的老年代空间时进行清除,但启动过早,会导致垃圾回收频繁,-XX:CMSInitiatingOccupancyFraction参数可调整阈值。在1.6版本时,此值为92%,大大提供了垃圾回收效率,但是会引发另一个问题Concurrent Mode Failure。此问题是,当预留空间无法满足浮动垃圾需求时发生的。这种情况下,CMS垃圾回收器会被强制转换为serial old,进行回收,而serial old会大大降低系统响应时间,需要更多的stop the world。

3.产生垃圾碎片。CMS垃圾回收器是基于标记清除算法的,所以会生成垃圾碎片,当大对象进来时,老年代没有足够空间提供时,会产生fullGC。CMS提-XX:UseCMSCompactAtFullCollection参数设置当老年代空间不足时,先进行整理,整理后不足才进行fullGc,但整理的过程非常慢,每次都进行整理会导致碎片问题没有了,停顿时间变长了。所以又提供了-XX:CMSFullGCsBeforeCompaction,这个参数用于设置执行多少次不整理的FullGc后,执行一次带整理的,默认值为0,每次都需要整理。

-XX:CMSInitiatingOccupancyFraction=92 和-XX:+UseCMSInitiatingOccupancyOnly

   -XX:+UseCMSInitiatingOccupancyOnly 只是用设定的回收阈值(上面指定的70%),如果不指定,JVM仅在第一次使用设定值,后续则自动调整.

 -XX:+CMSScavengeBeforeRemark

   在CMS GC前启动一次ygc,目的在于减少old gen对ygc gen的引用,降低remark时的开销-----一般CMS的GC耗时 80%都在remark阶段

你可能感兴趣的:(jvm,java,开发语言)