前言
cms是一个基于 标记-清除 算法的老年代垃圾回收器,综合考虑多方因素结合多个垃圾回收算法组成的,适用场景:重视服务器响应速度,要求系统停顿时间最短。这里要说明以下,这是一个老年代算法,年轻代怎么处理?不回收了嘛?这里其实年轻代是采用的其它算法,具体看策略,Java 参数可以选择策略。这里下文也会涉及到。
流程
- 1、初始标记(CMS initial mark)
“Stop The World”,仅仅只是标记一下 GC Roots 能直接关联到的对象,也就是根集合可直接到达的对象,但不会直接到叶子节点,还有遍历新生代对象,标记可达的老年代对象;速度很快。
这些灰色的节点就是初始标记的节点。
-
2、并发标记(CMS concurrent mark)
进行 GC RootsTracing 的过程,继续递归标记这些对象可达的对象,做可达性分析等
-
3、重新标记(CMS remark)
“Stop The World”,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
这里有一个讨论:重新标记的意义在哪?主要是标记那些数据?
remark阶段应该是以当前的gc roots开始再标记,但会跳过初始标记中已经被标记的数据,这样可以保证不会漏标。对于从存活到垃圾的这些对象来说,只能下次GC标记了。 -
4、并发清除(CMS concurrent sweep)
并行清理数据垃圾,回收内存。
耗时最长的是并发标记和并发清除,但并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。
优点缺点
优点:
- 并发收集
- 低停顿
缺点:
- CPU 资源消耗过大
并发设计会对CPU敏感,CMS 默认启动的回收线程数:(CPU数量+3)/4,也就是当 CPU 在4个以上时,并发回收时垃圾收集线程不少于 25%。 - CMS 收集器无法处理浮动垃圾
并发期间不用暂停,那么会导致这段期间产生的垃圾将不会被回收,只能下一次回收,这称作浮动垃圾。 - 产生空间碎片
本质上是一个标记-清除 垃圾回收算法,意味着收集结束时会有大量空间碎片产生,给大对象分配空间带来麻烦,如果老年代无空间可存放大对象,得不提前触发一次 Full GC 。当然CMS也提供来一些Java 参数来帮助解决,比如顶不住压力时开启内存碎片的合并整理过程、多少次回收后使用该整理算法。
组合策略
CMS要跟一个年轻代算法组合一起使用,HotSpot共有7种垃圾收集器,3个新生代垃圾收集器,3个老年代垃圾收集器,以及G1,一共构成7种可供选择的垃圾收集器组合。新生代与老年代垃圾收集器之间形成6种组合,每个新生代垃圾收集器都对应2种组合。下图表示垃圾回收组合:
年轻代:
- Serial 单线程
使用复制算法,在进行垃圾回收时会暂停其他所有的工作线程(stop the world,简称STW)直至回收结束,因此会影响用户的正常使用体验。 - ParNew
Serial的多线程版本,复制算法。 - Parallel
CMS(不带压缩)可以与Serial和ParNew进行组合,共2种组合垃圾回收算法。
-XX:-UseParNewGC -XX:+UseConcMarkSweepGC
Serial (DefNew) + CMS(Concurrent Mark Sweep)-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
Parallel (ParNew) + CMS(Concurrent Mark Sweep) + Serial Old(Serial Mark Sweep Compact)
参考博客
深入理解Java虚拟机
HotSpot的7种垃圾收集器组合
图解 CMS 垃圾回收机制原理,面试必知必会 !