CMS收集器的主要设计目标是:低应用停顿时间。它通过两种方式实现这一目标:
主要问题:由于不压缩带来的老年代堆碎片,或者在对象分配率高的情况下,都可能导致Full GC。
CMS收集器的GC周期主要由7个阶段组成,其中有两个阶段会发生stop-the-world,其他阶段都是并发执行的。(亦有4个阶段、6个阶段等说法)
初始化标记阶段,是CMS GC的第一个阶段,也是标记阶段的开始。主要工作是标记可直达的存活对象。
主要标记过程
程序执行情况
?
(Marked obj:老年代绿色圆点表示被初始化标记的对象。)
并发标记阶段,是CMS GC的第二个阶段。
在该阶段,GC线程和应用线程将并发执行。也就是说,在第一个阶段(Initial Mark)被暂停的应用线程将恢复运行。
并发标记阶段的主要工作是,通过遍历第一个阶段(Initial Mark)标记出来的存活对象,继续递归遍历老年代,并标记可直接或间接到达的所有老年代存活对象。
?
(Current obj:该对象的引用关系发生变化,对下一个对象的引用被删除。)
由于在并发标记阶段,应用线程和GC线程是并发执行的,因此可能产生新的对象或对象关系发生变化,例如:
对于这些对象,需要重新标记以防止被遗漏。为了提高重新标记的效率,本阶段会把这些发生变化的对象所在的Card标识为Dirty,这样后续就只需要扫描这些Dirty Card的对象,从而避免扫描整个老年代。
在并发预清洗阶段,将会重新扫描前一个阶段标记的Dirty对象,并标记被Dirty对象直接或间接引用的对象,然后清除Card标识。
标记被Dirty对象直接或间接引用的对象:
?
清除Dirty对象的Card标识:
?
本阶段尽可能承担更多的并发预处理工作,从而减轻在Final Remark阶段的stop-the-world。
在该阶段,主要循环的做两件事:
具体执行多久,取决于许多因素,满足其中一个条件将会中止运行:
预清理阶段也是并发执行的,并不一定是所有存活对象都会被标记,因为在并发标记的过程中对象及其引用关系还在不断变化中。
因此,需要有一个stop-the-world的阶段来完成最后的标记工作,这就是重新标记阶段(CMS标记阶段的最后一个阶段)。主要目的是重新扫描之前并发处理阶段的所有残留更新对象。
主要工作:
并发清理阶段,主要工作是清理所有未被标记的死亡对象,回收被占用的空间。
?
并发重置阶段,将清理并恢复在CMS GC过程中的各种状态,重新初始化CMS相关数据结构,为下一个垃圾收集周期做好准备。
?
参考
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collector
https://blogs.oracle.com/poonam/understanding-cms-gc-logs
https://blogs.oracle.com/jonthecollector/the-unspoken-phases-of-cms
https://plumbr.io/handbook/garbage-collection-algorithms-implementations#concurrent-mark-and-sweep
https://www.jianshu.com/p/2a1b2f17d3e4
http://psy-lob-saw.blogspot.com/2014/10/the-jvm-write-barrier-card-marking.html
https://www.cnblogs.com/littleLord/p/5380624.html
?
转载请注明来源:https://zhanjia.iteye.com/blog/2435266
?
更多文章,请关注公众号:二进制之路
?