CMS[Concurrent Mark Sweep]收集器是一种以获取最短回收停顿时间为目标的收集器。
目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的相应速度.
从名字就可以看出,CMS收集器是使用的标记清除算法,它的运作过程相当于前面几种收集器来说更为复杂,整个过程分为四个步骤:
- 初始标记,标记一下GC Roots能直接关联到的对象,速度很快
- 并发标记,进行GC Roots的Tracing过程
- 重新标记,为了修正并发标记阶段因用户程序继续运行而导致标记产生变动的那一部分的标记记录,这个阶段的停顿时间一般会比初始标记稍微长一些,但远比并发标记的停顿时间短
- 并发清除
由于整个过程中耗时最长的并发标记和并发清除的过程收集器线程可以与用户线程一起工作,所以从总体上说,CMS收集器的内存回收过程是与用户线程一起并发执行的.
CMS收集器是一款非常优秀的收集器,低停顿,并发收集,但也有3个明显的缺点:
- CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程[线程资源]而导致应用程序变慢,总吞吐量会降低
- CMS收集器无法处理浮动的垃圾,可能会导致”Concurrent Mode Failure”失败而导致另一次Full GC的产生。CMS并发清理阶段用户线程还在运行,会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当此收集中处理掉它们,只好留待下一次处理。这一部分就成为“浮动垃圾”,所以需要预留足够的内存空间给用户线程使用,预留多少空间可以通过“—XX:CMSInitiatingOccupancyFraction”的值来控制。如果预留空间太少,就会出现“ConCurrent Mode Failure”失败,虚拟机启动临时预案:临时启动Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就太长了。所以说预留空间太低容易导致大量 “Concurrent Mode Failure”失败,性能反而更低.
- 最后,CMS收集器是一款基于 “标记——清理”算法的收集器,会产生大量的空间碎片。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会有大量的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了一个—XX:+UseCMSCompactAtFullCollection开关参数(默认开启),用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间会变长。虚拟机设计者还提供了一个参数:—XX:CMSFullGCsBeforeCompaction,用于设置执行多少次不压缩的Fucc后,跟着来一次带压缩的(默认值为0, 表示每次进入Full GC时都进行碎片整理)