要深入理解 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
中,垃圾收集器的任务被划分为多个线程(如 CMSMark
和 CMSSweep
)进行并行处理。
主要源码文件:
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 级别的堆内存,也能保持极低的停顿时间。
核心类和方法
- ZGC:
ZGC
类是 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
:管理堆内存的类。
三者的主要区别总结
特性 | CMS | G1 | ZGC |
---|---|---|---|
停顿时间控制 | 较短,但有时会出现长时间的停顿 | 可配置,能精确控制每次 GC 的最大停顿时间 | 极低,几乎没有停顿时间 |
内存管理 | 标记-清除,年轻代和老年代分别回收 | 堆分为多个区域,细粒度回收 | 无传统的年轻代/老年代,堆划分为多个区域 |
回收策略 | 并发标记和清除 | 分区管理,回收时按区域选择 | 完全并发标记、搬迁和清理 |
性能 | 适用于中小型堆内存,性能一般 | 适用于大堆内存,性能较好 | 适用于超大堆内存,极低停顿 |
复杂度 | 较为简单,容易理解和实现 | 较复杂,支持灵活配置 | 非常复杂,支持极低延迟的目标 |
总结来说,CMS 更适用于中小型应用,对延迟要求较高但不需要处理超大内存;G1 适合大内存、复杂应用,可以精细控制 GC 停顿时间;ZGC 则为超大内存、高性能、低延迟的应用设计,能够处理 TB 级堆内存,并保持几乎为零的停顿时间。