1.CMS收集器
- CMS(Concurrent Mark Sweep)收集器是一种获取最短回收停顿时间为目标的收集器
- CMS收集器是一种基于"标记-清除"算法实现的收集器,整个过程分为四步
- 初始标记(CMS initial mark).该过程分为两步:
- 标记GC Roots可达的老年代对象
- 遍历新生代对象,标记可达的老年代对象
- 并发标记(CMS concurrent mark)
- 重新标记 (CMS remark)
- 并发清除 (CMS concurrent sweep)
- 初始标记、重新标记着两个步骤任然需要"Stop The World",初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记就是进行GC Roots Tracing 的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运行而导致标记产品变动的那一部分对象的标记记录。这个阶段的停顿时间一般会比初始标记阶段稍长一些。,但远比并发标记的时间短。
- 由于整个过程耗时最长的并发标记和并发清除都可以和用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
- CMS是一款优秀的收集器,它的主要优点在于:并发收集、低停顿。
- CMS 收集器的缺点
- CMS收集器对CPU非常敏感。其实面向并发设计的程序都对CPU比较敏感,在并发阶段,虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量降低。CMS默认启动的回收线程数是(CPU数量+3)/4,也就是当CPU在4个以上时,并发回收时,垃圾收集线程不少于25%的CPU资源,并且随着CPU数量的增加而下降。但是当CPU数量不足4个时,CMS对用户程序的影响就可能变的很大。如果CPU负载本来就很大,还要分出一半的运行能力去执行收集器线程,就可能导致用户程序的执行能力下降50%
- CMS收集器无法处理浮动垃圾。可能出现"Concurrent Mode Failure"失败而导致另一次Full GC。由于CMS并发清理阶段用户线程还在运行着,伴随着程序的运行自然就还会有新的垃圾不断产生,这一部分产生的垃圾,CMS无法在当次收集中处理掉他们,只要留待下一次GC再进行处理。这一部分产生的垃圾成为"浮动垃圾"。也是由于在垃圾收集阶段用户线程还要继续运行,那也就还需要预留足够的内存空间给用户线程使用。因此CMS收集器不能像其他收集器那样,等到老年代被填满后再进行垃圾回收。需要预留一部分空间供并发收集时的程序运行使用。
- 由于CMS采用"标记-清理"算法实现,所以当垃圾收集后,会产生大量的内存碎片。空间碎片过多,当程序运行需要分配大对象时,由于找不到连续的内存空间,而不得不提前触发一次Full GC.CMS采用了-XX:+UseCMSCompactAtFullCollection开关参数,用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程。内存碎片的整理是无法并发执行的,空间碎片问题没有了,但是随之而来的停顿时间变长了。因此,虚拟机设计者还提供了一个参数:-XX:CMSFullGCsBeforeCompaction来进行设置执行多少次不压缩的Full GC后进行一次带压缩的(默认是0.标识每次进入Full GC后都会带有一次内存压缩)
- 什么时候使用CMS收集器
如果引用程序对停顿比较敏感,并在在应用程序运行时可以提供更大的内存和更多的CPU(硬件相当牛逼),那么使用CMS收集器会给我们带来很多好处。还有就是如果JVM中,有相对较多存货时间较长的对象(老年代比较大)会更适合使用CMS
参考
周志明《深入理解Java虚拟机》
https://www.jianshu.com/p/2a1b2f17d3e4
写在最后
做一个灵魂和肉体分离的人,灵魂不受肉体的束缚,灵魂可以指挥肉体
网友评论