CMS 收集器
老年代垃圾收集器,使用标记-清除算法,并发收集。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。

疑问,图里为啥可以并发的阶段也要标出Safepoint
因为线程是在
Safepoint停下来的,又是在Safepoint启动了。
收集过程
- 初始标记(
CMS initial mark)stw - 并发标记(
CMS concurrent mark) - 重新标记(
CMS remark)stw - 并发清除(
CMS concurrent sweep)
整个过程中耗时最长的是并发标记和并发清除过程。但这两个过程用户线程都不需要停顿。
CMS的缺点
CMS是一款优秀的收集器,优点就是并发收集、低停顿,被称为“并发低停顿收集器”。
CMS是HotSpot虚拟机追求低停顿的第一次成功尝试。但也有明显缺点。
CMS收集器对处理器资源非常敏感
事实上,面向并发设计的程序都对处理器资源比较敏感。
在并发阶段虽然用户线程不会停顿,但会因为占用部分线程而导致应用程序变慢,降低吞吐量。
CMS默认启动的回收线程树是(处理器核心+3)/ 4。处理器核心在四个或以上,垃圾收集线程只占用不超过25%的处理器运算资源。
但当处理器核心数不足4个时,CMS对用户程序的影响就可能变得很大。如果应用本身的处理器负载就很高,还要分出一般运算能力
去执行垃圾收集,会导致用户程序执行速度忽然大幅降低。
为了缓解这种情况,虚拟机提供了一种称为“增量式并发收集器”(Incremental Concurrent Mark Sweep/i-CMS)的CMS收集器变种,
在并发标记、清理的时候让收集器线程和用户线程交替运行,尽量减少垃圾收集线程的独占资源的时间,这样整个垃圾收集过程会变长,
但对用户程序的影响会显得较少一些。实践证明,效果一般,JDK7开始,i-CMS就被声明为deprecated,在JDK9被完全废弃。
无法处理浮动垃圾(Floating Garbage)
浮动垃圾:CMS并发标记和并发清理阶段,用户线程还在运行,运行就可能有新的垃圾对象产生,这部分对象是在标记过程结束后的,
CMS无法在当次收集中处理它们,只能留到下一次垃圾收集时再清理掉。这部分垃圾就是浮动垃圾。
Concurrent Mode Failure:同样由于垃圾收集阶段用户线程还在执行,所以需要预留足够内存空间提供给用户线程,
如果预留的空间无法满足程序分配新对象的需求,就会出现一次“并发失败”(Concurrent Mode Failure),这时虚拟机不得不启动预备方案,
冻结用户线程的执行,临时启动Serial Old收集器重新进行老年代的垃圾收集。提前触发一次Full GC。
预留的空间:在
JDK5默认配置下,CMS收集器当老年代使用了68%的空间后就会被激活,可以通过-XX:CMSInitiatingOccupancyFraction值来提高
CMS的触发百分比,降低回收频率。到JDK6默认值提升至92%。
CMS无法像其他垃圾收集器一样等待整个老年代几乎被填满再进行收集。
大对象分配问题
CMS是一款基于“标记-清除”算法实现的收集器,意味着进行垃圾收集后是会产生空间碎片的。
空间碎片过多时,往往无法找到足够的连续空间来分配大对象,进而不得不触发一次Full GC,
为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关的参数
(默认开启,JDK9开始废弃),用于在CMS收集器不得不进行Full GC时开启内存碎片的合并整理过程,
由于移动对象CMS收集器无法并发,因此这样会导致停顿时间变长,因此还有一个-XX:CMSFullGCBeforeCompaction
(JDK9开始废弃),这个参数要求CMS收集器在执行过若干次不整理空间的Full GC之后,下一次Full GC前会先
进行碎片整理(默认值是0,表示每次进入Full GC时都进行碎片整理)