CMS为何采用标记-清除算法

年老代并发收集器-CMS

clipboard.png

-XX:+UseConcMarkSweepGC
新生代:复制算法,默认搭配ParNewGC,并行
年老代:标记-清除,并发(若是发生Concurrent Mode Fail,则使用SerialOld作后备收集器)java

并行与并发的区别

clipboard.png

CMS的执行周期

clipboard.png

  • 初始标记:STW,单线程,因为是从GCRoot寻找直达的对象,速度快算法

  • 并发标记:与应用线程一块儿运行,是CMS最主要的工做阶段,经过直达对象,扫描所有的对象,进行标记多线程

  • 从新标记:STW,修正并发标记时因为应用程序还在并发运行产生的对象的修改,多线程,速度快,须要全局停顿并发

  • 并发清除:与应用程序一块儿运行,为什么采用清除算法?CMS主要关注低延迟,于是采用并发方式,清理垃圾时,应用程序还在运行,如何采用压缩算法,则涉及到要移动应用程序的存活对象,此时不停顿,是很难处理的,通常须要停顿下,移动存活对象,再让应用程序继续运行,但这样停顿时间变长,延迟变大,因此CMS采用清除算法。性能

后备收集器:SerialOld

clipboard.png

并发GC,吞吐量降低,采用标记清除,碎片多,占用额外内存,不能在堆空间满时清理,触发GC:
清理时,应用程序还在运行此时若是预留的空间不够应用程序申请的空间的话,则会触发Concurrent Mode Fail,此时便会启用后备收集器:SerialOld进行GC,产生全局停顿spa

并发模式失败(Concurrent Mode Failure)

CMS收集器没法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而致使另外一次Full GC的产生。线程

(1)若是对象提高到年老代的速度太快,而CMS收集器不能保持足够多的可用空间时,就会致使年老代的运行空间不足;
(2)当年老代的碎片化达到某种程度,使得没有足够空间容纳重新生代提高上来的对象时,也会发生并发模式失败。设计

当发生并发模式失败时,年老代将进行垃圾收集以释放可用空间,同时也会整理压缩以消除碎片,这个操做须要中止全部的java应用线程,而且须要执行至关长时间。3d

浮动垃圾

因为CMS并发清理阶段用户线程还在运行着,伴随程序运行天然就还会有新的垃圾不断产生,这一部分垃圾出如今标记过程以后,CMS没法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为“浮动垃圾”。对象

CMSInitiatingOccupancyFraction

也是因为在垃圾收集阶段用户线程还须要运行,那也就还须要预留有足够的内存空间给用户线程使用,所以CMS收集器不能像其余收集器那样等到老年代几乎彻底被填满了再进行收集,须要预留一部分空间提供并发收集时的程序运做使用

在JDK 1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,若是在应用中老年代增加不是太快,能够适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提升触发百分比,以便下降内存回收次数从而获取更好的性能,

在JDK 1.6中,CMS收集器的启动阈值已经提高至92%。要是CMS运行期间预留的内存没法知足程序须要,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启动后备预案:临时启用Serial Old收集器来从新进行老年代的垃圾收集,这样停顿时间就很长了。

因此说参数-XX:CMSInitiatingOccupancyFraction设置得过高很容易致使大量“Concurrent Mode Failure”失败,性能反而下降。

CMS内存整理

CMS是一款基于“标记—清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。

空间碎片过多时,将会给大对象分配带来很大麻烦,每每会出现老年代还有很大空间剩余,可是没法找到足够大的连续空间来分配当前对象,不得不提早触发一次Full GC。

为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程,内存整理的过程是没法并发的,空间碎片问题没有了,但停顿时间不得不变长。

虚拟机设计者还提供了另一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都进行碎片整理)。

Promotion Failure

过早提高(Premature Promotion),MinorGC过程当中,Survivor可能不足以容纳Eden和另一个Survivor中存活的对象,若是Survivor中的存活对象溢出,多余的对象将被移到年老代。

在MinorGC过程当中,若是年老代满了没法容纳更多的对象,则MinorGC以后,一般会进行FullGC,这将致使遍历整个java堆,这称为提高失败(Promotion Failure)

相关文章
相关标签/搜索