Java 的 CMS 垃圾回收流程
Java 的 CMS 垃圾回收流程
CMS(Concurrent Mark-Sweep)垃圾回收器 是一种并发垃圾回收器,旨在减少垃圾回收时的停顿时间,适用于对低延迟要求较高的应用。CMS 主要通过并发标记和并发清除阶段来减少暂停时间。CMS 主要包含以下几个阶段:
1. CMS 的垃圾回收流程
CMS 的垃圾回收过程包括以下几个阶段:
1.1 初始标记(Initial Mark)
- 触发条件:在进行标记之前,首先需要执行初始标记阶段。
- 过程:
- 停止应用线程(STW)。
- 标记根对象(GC Roots)直接可达的对象。
- 这一步骤只标记 GC Roots 引用的对象,不会遍历整个堆,时间较短。
1.2 并发标记(Concurrent Mark)
- 触发条件:初始标记完成后,进入并发标记阶段。
- 过程:
- 这一阶段与应用线程并发进行,即垃圾回收线程和应用线程同时执行。
- 从根对象出发,扫描堆中所有的对象,标记所有可达对象。
- 由于并发执行,标记过程中对象的引用可能发生变化,但 CMS 会通过 写屏障 机制来记录对象的引用变化。
- 该阶段的时间较长,但由于与应用线程并发执行,所以不需要额外的 STW 时间。
1.3 重新标记(Remark)
- 触发条件:并发标记阶段完成后,进入重新标记阶段。
- 过程:
- 停止应用线程(STW)。
- 通过扫描和处理并发标记期间的引用变化,修正并发标记时遗漏的引用。
- 由于这一步涉及到修正标记图,因此需要暂停应用线程,时间比初始标记略长。
1.4 并发清理(Concurrent Sweep)
- 触发条件:重新标记阶段完成后,进入并发清理阶段。
- 过程:
- 这一阶段与应用线程并发进行。
- 垃圾回收器扫描整个堆,清除未被标记的对象(即垃圾对象)。
- 由于并发执行,该过程不会影响应用程序的运行。
1.5 并发重置(Concurrent Reset)
- 触发条件:清理阶段完成后,准备进行下一次垃圾回收。
- 过程:
- 重置内部的数据结构,为下一次垃圾回收做准备。
- 这通常是一个非常短的阶段,可能会与应用线程并发执行。
2. CMS 垃圾回收流程的关键点
2.1 写屏障(Write Barrier)
- 为了保证并发标记的准确性,CMS 使用了写屏障。当应用线程修改对象引用时,写屏障会记录修改,确保这些修改能够被垃圾回收器捕捉并标记。
- 例如,在并发标记阶段,如果对象引用发生变化,写屏障会将相关的变化记录到“记忆集”中,以便后续在重新标记阶段处理。
2.2 记忆集(Remembered Set)
- 记忆集是用于记录跨代引用的集合。由于 CMS 采用的是分代垃圾回收机制,跨代引用(即从年轻代到老年代的引用)会通过记忆集来跟踪,确保标记过程不漏掉跨代引用。
3. CMS 的优缺点
优点:
- 低停顿时间:通过并发标记和并发清理,CMS 将大部分工作与应用线程并行执行,减少了 STW 的停顿时间。
- 较短的垃圾回收暂停:特别适合对响应时间要求高的应用程序,如金融、电商等领域。
- 适应大堆内存:CMS 可在堆内存较大的情况下保持较低的停顿时间。
缺点:
- 垃圾回收效率较低:虽然并发进行,但仍有清理过程需要耗费较长时间,尤其在老年代垃圾量较多时,可能出现停顿时间较长的问题。
- 可能发生 Concurrent Mode Failure(并发模式失败):如果老年代空间不足,无法为新对象分配内存,CMS 会触发 Full GC,导致全停顿,影响应用性能。
- 内存碎片:由于 CMS 使用的是标记-清除算法,可能会导致老年代内存碎片化,从而降低内存的利用率。
4. CMS 与其他垃圾回收器的对比
4.1 与 Serial GC 对比
- Serial GC 是一个单线程的垃圾回收器,所有的回收操作都需要停顿应用程序。
- 相比之下,CMS 采用并发标记和清理的方式,可以减少停顿时间,适合需要低延迟的应用。
4.2 与 G1 对比
- G1 是一个区域化的垃圾回收器,可以更精细地控制回收过程,通过并发标记、清理以及分代回收,优化停顿时间。
- CMS 更倾向于老年代的清理,而 G1 在处理混合垃圾回收时会优先回收高垃圾比例的区域,更加灵活。
5. 总结
CMS 垃圾回收器采用并发标记和并发清理的方式,显著降低了垃圾回收的停顿时间。其主要流程包括:
- 初始标记:标记 GC Roots 可达对象。
- 并发标记:与应用线程并发进行,标记所有可达对象。
- 重新标记:处理并发标记期间的引用变化。
- 并发清理:与应用线程并发清理垃圾对象。
CMS 的设计旨在减少停顿时间,但也存在可能出现内存碎片和并发模式失败的问题。对于要求低延迟的应用,CMS 是一个理想的选择,但对于大堆内存应用,可能需要更强大的 G1 回收器来替代。