要深入理解 CMS、G1 和 ZGC 这三种垃圾收集器的设计与实现,分析它们的源码是一个非常有效的途径。HotSpot 是 Java 的默认虚拟机,它的垃圾收集器是通过多个类和方法来实现的,我们可以通过查看 HotSpot 源码中相关部分,来更好地理解它们的实现细节和区别。

1. CMS (Concurrent Mark-Sweep) 源码分析

CMS 是基于标记-清除算法的垃圾收集器,它旨在减少垃圾收集的停顿时间。CMS 的设计关键在于标记阶段的并发性以及垃圾回收过程中“Stop-the-World”停顿的减少。要理解其实现,我们需要查看几个关键部分。

核心类和方法

  • ConcurrentMarkSweep:这是 CMS 垃圾收集器的主要类,继承自 GarbageCollector。它定义了垃圾收集的流程,包括并发标记、清除等。
  • CMSTask:这是执行并发标记和清理等任务的核心类。CMSTask 通过与 ConcurrentMarkSweep 协同工作,实现垃圾收集过程的并发执行。

核心流程

CMS 的垃圾收集可以分为几个阶段:

  • Initial Mark: 初始标记阶段是通过 CMSTask::initialMark 来触发的,在这一阶段所有的根对象会被标记。在此阶段,系统会停顿。
  • Concurrent Mark: 在并发标记阶段,垃圾收集器会并发地扫描堆中的对象,标记存活的对象。此阶段不会阻塞应用程序。
  • Concurrent Preclean: 在这个阶段,JVM 会尽量清除一些不再需要的对象。
  • Remark: 这个阶段会在“Stop-the-World”停顿时完成那些漏掉的标记工作。
  • Sweep: 清除标记为垃圾的对象,并整理内存。

CMS 在并发标记阶段,通过 ConcurrentMarkSweep::collect 方法来触发垃圾收集器的工作。在 CMS 中,垃圾收集器的任务被划分为多个线程(如 CMSMarkCMSSweep)进行并行处理。

主要源码文件:

  • src/hotspot/share/gc/cms/CMSCollector.cpp:CMS 垃圾收集器的核心实现。
  • src/hotspot/share/gc/cms/CMSTask.hpp:任务类,用于标记和清除对象。
  • src/hotspot/share/gc/cms/CMSParNewGeneration.cpp:CMS 的“年轻代”收集器。

2. G1 (Garbage First) 源码分析

G1 是一种新型的垃圾收集器,旨在同时优化吞吐量和停顿时间。与 CMS 不同,G1 采用堆划分为多个 Region,并在不同区域进行垃圾收集。它能够更灵活地控制每个 Region 的回收策略,并且能够精确控制每次 GC 的最大停顿时间。

核心类和方法

  • G1CollectorPolicy:这是 G1 垃圾收集的策略类。它包含了控制垃圾回收的逻辑,如每个阶段的回收策略和停顿时间目标等。
  • G1HeapRegion:堆被分为多个 Region,每个 Region 有自己的回收策略。这个类管理 Region 内的内存。
  • G1CollectorThread:执行 G1 垃圾收集器的任务,包括标记、清理、整理等。

核心流程

G1 的工作过程比 CMS 更加复杂,它的主要特点是对内存的细粒度划分以及对每个 Region 的独立回收。

  • Initial Mark:类似于 CMS,G1 在进行初始标记时会标记根对象,这个过程会停顿。
  • Concurrent Mark:G1 在并发标记阶段,开始标记堆内存中存活的对象。
  • Mixed Collection:在 G1 中,垃圾收集器可以同时回收多个 Region,这个过程称为混合回收。G1 会根据每个 Region 的垃圾情况进行有选择性的回收。
  • Final Mark:标记最后漏掉的对象,类似于 CMS 的 Remark。

G1 在回收过程中,不同 Region 之间的回收策略是独立的,这样能够根据每个 Region 的实际垃圾量和停顿时间目标来做优化。G1 会根据 -XX:MaxGCPauseMillis 设置,动态调整每个 GC 回收周期的时间,以尽量保持停顿时间在预定目标内。

主要源码文件:

  • src/hotspot/share/gc/g1/G1CollectorPolicy.cpp:G1 垃圾收集的核心策略类。
  • src/hotspot/share/gc/g1/G1HeapRegion.cpp:G1 垃圾收集器中每个堆区域的管理类。
  • src/hotspot/share/gc/g1/G1CollectorThread.cpp:执行 G1 垃圾收集任务的线程类。

3. ZGC (Z Garbage Collector) 源码分析

ZGC 是一个低延迟的垃圾收集器,设计目的是将垃圾收集的停顿时间控制在几毫秒之内。ZGC 的核心理念是“并发”和“分代回收”相结合,并且通过“并发对象搬迁”来保证高效的内存回收。它的目标是即使处理 TB 级别的堆内存,也能保持极低的停顿时间。

核心类和方法

  • ZGCZGC 类是 ZGC 收集器的主要类,负责控制垃圾收集的流程。
  • ZGCTask:ZGC 的任务类,负责管理并发标记、重定位和清理对象等工作。
  • ZGCHeap:管理堆的类,ZGC 不使用传统的年轻代和老年代,而是将堆划分为多个区域(类似 G1),但每个区域的回收策略不同。

核心流程

ZGC 的设计目标是保证低延迟,并且大部分垃圾收集任务是并发执行的。ZGC 通过“分代”策略和“并发搬迁”来提高性能。

  • Concurrent Marking:ZGC 在标记阶段通过并发标记存活对象,不会暂停应用线程。
  • Concurrent Relocation:ZGC 使用着色技术来标记对象,并通过并发搬迁来整理堆内存,避免停顿。
  • Concurrent Cleanup:清理阶段和标记阶段一样,是并发执行的。ZGC 会在不停止应用线程的情况下完成回收工作。

ZGC 主要通过“并发”来处理垃圾收集,避免了长时间的“Stop-the-World”停顿。

主要源码文件:

  • src/hotspot/share/gc/z/zgc.cpp:ZGC 的主入口,处理垃圾收集的各个阶段。
  • src/hotspot/share/gc/z/ZGCTask.cpp:ZGC 的任务执行类,包含并发标记、清理等任务。
  • src/hotspot/share/gc/z/ZGCHeap.cpp:管理堆内存的类。

三者的主要区别总结

特性CMSG1ZGC
停顿时间控制较短,但有时会出现长时间的停顿可配置,能精确控制每次 GC 的最大停顿时间极低,几乎没有停顿时间
内存管理标记-清除,年轻代和老年代分别回收堆分为多个区域,细粒度回收无传统的年轻代/老年代,堆划分为多个区域
回收策略并发标记和清除分区管理,回收时按区域选择完全并发标记、搬迁和清理
性能适用于中小型堆内存,性能一般适用于大堆内存,性能较好适用于超大堆内存,极低停顿
复杂度较为简单,容易理解和实现较复杂,支持灵活配置非常复杂,支持极低延迟的目标

总结来说,CMS 更适用于中小型应用,对延迟要求较高但不需要处理超大内存;G1 适合大内存、复杂应用,可以精细控制 GC 停顿时间;ZGC 则为超大内存、高性能、低延迟的应用设计,能够处理 TB 级堆内存,并保持几乎为零的停顿时间。