探究JVM(八)简单易懂的CMS垃圾收集器,一下子就清楚工作流程

引言:CMS是第一款用户线程能够和收集器线程同时工作的垃圾收集器。相较于后来的G1和ZGC垃圾收集器来说,CMS的工作流程简单,易于理解。

工作流程

  1. 初始标记阶段:用户线程暂停,扫描根集合,标记能够直接关联到的对象。
  2. 并发标记阶段:恢复用户线程,并发扫描对象图并标记对象。
  3. 重新标记阶段:用户线程暂停,处理并发标记阶段记录下的引用修改。
  4. 并发清理阶段:恢复用户线程,并发清理可回收对象。

值得一提的是CMS采用增量更新的方法来解决并发标记阶段引用的修改问题,具体的内容可以看我之前关于增量更新和原始快照的博客。

CMS的优缺点

(1)CMS的优点比较直接,CMS的响应速度快,用户体验好,因为大部分时间用户线程可以和GC线程同时工作。
(2)CMS对处理器的资源要求比较高,因为在并发阶段有部分处理器资源要被用来处理并发标记,如果处理器的核心较少时,用户线程和GC线程争抢资源,会导致用户线程的执行速度下降。而且由于用户线程和GC线程同时工作,其中对于线程切换和线程保护的资源浪费也是不可以忽略的开销。这里引用CodeCentric Blog的一篇文章来解释这种开销:

This, however, causes additional costs for thread scheduling: direct costs through context switches and indirect costs because of cache effects. Together with the costs for additional JVM-internal safety measures, this means that each GC comes along with some non-negligible overhead, which adds up with the time taken by the GC threads to perform their actual work.

用户线程和GC线程同时运行时,随着而来的是上下文切换,内存影响,安全措施等一系列除了真正工作以外的开销。
(3)CMS垃圾收集器使用的增量更新无法解决浮动垃圾问题,虽然相较于原始快照浮动垃圾略少,但还是存在。当并发阶段,浮动垃圾过多时,新对象无法分配,这时候就会启动Serial Old来整理老年代空间,暂停时间就会变长。
(4)CMS采用的是标记清除算法,内存空间碎片化,所以有可能出现大对象无法在连续空间分配的情况,这时候就要启动Serial Old垃圾收集器进行Full GC,暂停时间同样会变长。
(5)要注意的是Serial Old GC收集范围是整个堆和方法区,因而是Full GC,这里引用R大的博客原文:

“Serial Old GC的算法是mark-compact(也可以叫做mark-sweep-compact,但要注意它不是“mark-sweep”)。具体算法名是LISP2。它收集的范围是整个GC堆,包括Java heap的young generation和old generation,以及non-Java heap的permanent generation。因而它是full GC。”

总结

(1)关于GC线程额外开销的博客:https://blog.codecentric.de/en/2013/01/useful-jvm-flags-part-6-throughput-collector/
(2)CMS采用增量更新解决并发标记问题,具体内容可以看我之前关于增量更新和原始快照的博客。

上一篇:SAP 电商云 Spartacus UI 页面布局的设计原理


下一篇:一键帝国CMS快速重置管理员密码工具