CMS 的问题
我觉得这些问题提的非常好,其实不看本篇解答,直接根据问题的角度去学习就足够了。
问题
带着问题去学习一个东西,才会有目标感,我先把一直以来自己对CMS的一些疑惑罗列了下,希望这篇学习笔记能解决掉这些疑惑,希望也能对你有所帮助。
CMS出现的初衷、背景和目的?
CMS的适用场景?
CMS的trade-off是什么?优势、劣势和代价
CMS会回收哪个区域的对象?
CMS的GC Roots包括那些对象?
CMS的过程?
CMS和Full gc是不是一回事?
CMS何时触发?
CMS的日志如何分析?
CMS的调优如何做?
CMS扫描那些对象?
CMS和CMS collector的区别?
CMS的推荐参数设置?
为什么ParNew可以和CMS配合使用,而Parallel Scanvenge不可以?
基础知识
你需要对 GC 就基础知识,参见 java gc 详解
- 拓展阅读
CMS
CMS收集器:Mostly-Concurrent收集器,也称并发标记清除收集器(Concurrent Mark-Sweep GC,CMS收集器),它管理新生代的方式与Parallel收集器和Serial收集器相同,而在老年代则是尽可能得并发执行,每个垃圾收集器周期只有2次短停顿。
CMS的初衷和目的
为了消除Throught收集器和Serial收集器在Full GC周期中的长时间停顿。
CMS的适用场景
如果你的应用需要更快的响应,不希望有长时间的停顿,同时你的CPU资源也比较丰富,就适合适用CMS收集器。
CMS的过程
CMS的正常过程
这里我们首先看下CMS并发收集周期正常完成的几个状态。
###(STW)初始标记
这个阶段是标记从GcRoots直接可达的老年代对象、新生代引用的老年代对象,就是下图中灰色的点。
这个过程是单线程的。
并发标记
由上一个阶段标记过的对象,开始tracing过程,标记所有可达的对象,这个阶段垃圾回收线程和应用线程同时运行,如上图中的黄色的点。
在并发标记过程中,应用线程还在跑,因此会导致有些对象会从新生代晋升到老年代、有些老年代的对象引用会被改变、有些对象会直接分配到老年代,这些受到影响的老年代对象所在的card会被标记为dirty,用于重新标记阶段扫描。
这个阶段过程中,老年代对象的card被标记为dirty的可能原因,就是下图中绿色的线:
预清理
预清理,也是用于标记老年代存活的对象,目的是为了让重新标记阶段的STW尽可能短。这个阶段的目标是在并发标记阶段被应用线程影响到的老年代对象,包括:
(1)老年代中card为dirty的对象;
(2)幸存区(from和to)中引用的老年代对象。因此,这个阶段也需要扫描新生代+老年代。【PS:会不会扫描Eden区的对象,我看源代码猜测是没有,还需要继续求证】
可中断的预清理
这个阶段的目标跟“预清理”阶段相同,也是为了减轻重新标记阶段的工作量。
可中断预清理的价值:在进入重新标记阶段之前尽量等到一个Minor GC,尽量缩短重新标记阶段的停顿时间。
另外可中断预清理会在Eden达到50%的时候开始,这时候离下一次minor gc还有半程的时间。
这个还有另一个意义,即避免短时间内连着的两个停顿。
TODO…