CMS
CMS
垃圾回收器,全称 Concurrent Mark Sweep
并发标记-清除,从名字上面我们也可以看出这个垃圾回收器是基于标记清除算法实现的。首先"并发"表示 GC
线程可以和用户线程并发执行,同时既然是标记-清除算法,说明这个垃圾回收器会产生很多碎片,这是标记-清除算法的缺点。同时 CMS
是作用于老年代的,老年代的垃圾回收频率相对年轻代会低一点。
CMS
的垃圾回收有四个过程
- 初始标记:
- 并发标记:
- 重新标记:
- 并发清除:
初始标记的时候是一个 STW (stop the world)
的过程,所有的用户线程都会停止,这个时候只是标记一下 GC Roots
能直接达到的对象,由于只是标记一层所以整个速度相对会比较快。
并发标记是一个 GC Roots
扫描的过程,会扫描整个链路标记可以回收的对象;由于整个的链路会比较长,所以相对会耗时久一点,不过由于这个过程是并发的,所以对用户线程运行是没有影响的。
重新标记顾名思义是一个再次标记的过程,同时也是会 STW
,之所以会有这个重新标记的过程,是因为在上一步并发标记的过程中,用户线程依旧在运行,所以对象的引用关系会发生变化同时在运行的时候也会产生新的垃圾。这里只会标记在上一步有发生变化的对象,虽然会 STW
不过速度也较快。
并发清除是最后一个阶段,这个阶段由于需要清除之前扫描的所有垃圾对象,所以会相对比较耗时,不过这个阶段是可以并发进行的所以对用户线程的运行不会有影响。
经过上面的四个过程就完成了一次完整的 GC
,前面我们提到整个 CMS
垃圾回收器是基于标记-清除算法的,先通过三个过程标记出需要清理的对象,然后再进行清理。整个过程中初始标记和重新标记会触发 STW
,其他两个阶段是并发进行的。标记-清除算法会产生内存碎片,所以不适合需要频繁回收的年轻代,所以只适合老年代。产生碎片是 CMS
的缺点,并发是 CMS
的优点,毕竟任何一个收集器都会有优缺点。
G1
前面我们聊完了 CMS
,接下来我们聊一下 G1
,G1
全称 Garbage First
,在讲 G1
垃圾回收器的细节之前,我们首先要知道的是 G1
对整个堆的空间做了重新的定义。G1
中的老年代和年轻代已经不再是物理隔离的了,而是逻辑隔离。在 G1
中整个堆空间被分成了一个个相同大小的 Region
块,多个 Region
块在逻辑上组成了年轻代和老年代。
这样做的目的是因为在进行垃圾回收的时候不需要进行整个堆空间的扫描,同时可以根据指定停顿时间来进行垃圾回收。G1
会将每个 Region
的回收成本进行量化,从而达到一个成本控制,可以在限定的停顿时间内完成回收,这是 G1
的最大的特点。
G1
回收也分为四个过程:
- 初始标记:初始标记与
CMS
也是只扫描GC Roots
直达的对象,这阶段同样也要STW
,不过时间也很短; - 并发标记:从
GC Roots
开始堆中对象进行可达性分析,找出存活的对象,这个阶段耗时较长,但是可以与用户程序并发执行; - 最终标记:最终标记和
CMS
的重新标记的思路一直,也是为了修正并发标记期间由于用户程序并发运行而导致标记产生变动的那一部分对象,不过不同的是G1
会将这段时间对象变化记录在线程Remembered Set Logs
里面,最终标记阶段需要把Remembered Set Logs
的数据合并到Remembered Set
中,这个阶段需要停顿线程,不过是可并行执行; - 筛选回收:最后一步筛选回收是
G1
与CMS
最大的不同之处,G1
首先会对各个需要回收的Region
代价进行量化和排序,在结合用户所期望的GC
停顿时间来制定回收计划,通过-XX:MaxGCPauseMillis
参数来指定期望的回收时间。这个阶段也可以做到与用户程序一起并发执行,但是因为只回收一部分Region
,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。
上面提到了一个 Remembered Set
记忆集,是用来记录对象引用的,在并发标记的时候有对象引用发生变更的时候会记录到这里,等到最终标记的时候进行修正。整体上来看 G1
采用的是标记-整理的算法来进行垃圾回收,也不会像 CMS
那样会产生内容碎片,所以 G1
同时可以进行年轻代和老年代的垃圾回收,相比 CMS
会更灵活一点,而且也因为 G1
将内存划分成 Region
了,也不会造成复制算法带来的空间浪费的问题。
总结
首先CMS 和 G1 都是并发和分代的垃圾回收器,并且都是低延迟的;CMS 是基于标记-清除算法的,只适合在老年代使用,不可预测停顿时间,同时年轻代和老年代是物理隔离的。G1 是基于标记-整理的高吞吐,可预测停顿时间的垃圾回收器,可以同时使用在年轻代和老年代,同时年轻代和老年代是逻辑隔离的。
特点 | G1 | CMS |
算法 | 标记-整理 | 标记-清除 |
年轻代和老年代隔离方式 | 逻辑隔离 | 物理隔离 |
停顿时间可预测行 | 是 | 否 |
并发和分代 | 支持 | 支持 |
吞吐量 | 高 | 低 |
使用场景 | 年轻代,老年代 | 老年代 |
低延时 | 是 | 是 |