作者:程序员小袁
关键词:JVM、垃圾回收、G1、ZGC、Shenandoah、JDK23
一、前言
从 JDK 8 到 JDK 23,HotSpot JVM 的垃圾回收器体系经历了一次完整的"进化":
从早期的 Serial / Parallel GC 到中期的 CMS / G1 ,再到如今的 ZGC / Shenandoah。
如果说早期 GC 是在追求"最大化吞吐",
那么今天的 JVM,更关注的是 "极低延迟 + 可扩展性"。
二、版本演进总览
下表汇总了从 JDK 8 到 JDK 23 的所有主要 GC 实现,以及每个版本的默认 GC。
JDK 版本 | 支持的 GC | 默认 GC / 重大变化 | 说明 |
---|---|---|---|
JDK 8 | Serial、Parallel、CMS、G1 | Parallel GC | G1 可用,但非默认 |
JDK 9 | Serial、Parallel、CMS、G1 | G1 | JEP 248:G1 成为默认 |
JDK 10--11 | Serial、Parallel、G1、ZGC(实验) | G1 | ZGC 首次出现 (实验性) |
JDK 12--14 | Serial、Parallel、G1、ZGC、Shenandoah | G1 | CMS 正式移除 |
JDK 15--20 | Serial、Parallel、G1、ZGC、Shenandoah | G1 | ZGC、Shenandoah 稳定化 |
JDK 21--23 | Serial、Parallel、G1、ZGC(代际)、Shenandoah | ZGC (Generational) | OpenJDK 23 将代际 ZGC 设为默认 |
📌 说明:
- CMS 在 JDK 14 被彻底移除。
- ZGC 从 JDK 11 试验 → JDK 15 稳定 → JDK 23 默认。
- Shenandoah 主要由 RedHat 主导,面向低延迟场景。
三、举个例子-GC 家族总览与"班级管理"比喻
在 JVM 世界中,"对象"就像班级里的学生:
有的学生刚入学(新生代),有的读了几年(老年代)。
GC 的职责,就是定期清理毕业的学生(不可达对象),并维持教室整洁(内存紧凑)。
1️⃣ Serial GC ------ 单线程老师,全班停课整理
原理概述:
- 单线程执行标记、清除、压缩;
- Stop-The-World,全班暂停;
- 年轻代采用复制算法,老年代使用标记-压缩。
举个例子:
老师一个人打扫教室,全班必须静音等着。
她先清点名单(标记),再请离校的学生走人(清除),最后把桌椅搬紧凑(压缩)。
特点:
- 简单可靠;
- 适合单核、小堆场景;
- 不适合多核或大型服务器。
2️⃣ Parallel GC ------ 多个老师并行清理,但仍停课
原理概述:
- 多线程 GC;
- 吞吐优先;
- 年轻代复制,老年代标记-压缩;
- 全程 Stop-The-World。
举个例子:
几个老师一起清点名单、搬桌椅,分工合作更快;
但上课仍得暂停。
特点:
- 吞吐量高;
- 延迟不敏感;
- 适合批处理型任务或后台计算。
3️⃣ CMS(Concurrent Mark-Sweep)------ 偷着打扫,不打断上课
原理概述:
- 老年代并发标记 + 清除;
- 几乎不压缩,容易碎片化;
- 有短暂停顿阶段:Initial Mark、Remark;
- 并发失败时会退化成 Full GC。
举个例子:
老师上课时偷偷做卫生检查:
先快速点名(Initial Mark),
再课上暗中观察学生是否离开(Concurrent Mark),
中途再核对一次名单(Remark),
最后悄悄请离开的同学离开(Sweep)。
因为不挪桌椅,会留下空位(内存碎片)。
特点:
- 老年代低停顿;
- 可能出现碎片;
- 已在 JDK 14 移除。
4️⃣ G1 GC(Garbage First)------ 分区清理,按收益优先
原理概述:
- 堆被分成若干 Region;
- 标记后计算各区"垃圾密度";
- 优先回收回报最高的区;
- 可控制目标停顿时间 (
-XX:MaxGCPauseMillis
)。
举个例子:
教室划成许多小区块。
老师优先整理那些空位最多、收益最高的区块,
其他区继续上课,不打扰整体。
特点:
- 延迟可控;
- 兼顾吞吐;
- 大堆场景首选;
- 自 JDK 9 起默认。
示意图:
堆划分为多个 Region 标记存活对象 计算回收收益 优先回收高收益区 压缩存活对象到新 Region
5️⃣ Shenandoah GC ------ 上课同时搬桌椅
原理概述:
- 并发标记 + 并发压缩;
- 借助读写屏障维持引用一致;
- 停顿时间与堆大小几乎无关;
- RedHat 主导,低延迟专用。
比喻:
老师在上课过程中边讲课边换座位。
系统实时更新座位表(屏障机制),
学生之间互相呼叫不会搞错位置。
特点:
- 停顿极短;
- 实现复杂;
- 适用于延迟敏感系统。
6️⃣ ZGC ------ 不停课的"无声整理大师"
原理概述:
- 几乎全并发;
- 使用"染色指针(Colored Pointer)"追踪对象状态;
- 读屏障自动修正引用;
- 支持数 TB 级堆;
- JDK 23 引入 代际 ZGC:将年轻代与老年代分开管理,提升效率。
比喻:
老师几乎不打断上课。
她给每个学生的名牌上贴上颜色(染色指针),
后台悄悄记录谁离开、谁搬家。
学生互相点名时,如果某位同学换了座位,系统会自动指向新位置(指针重映射)。
特点:
- 停顿 < 10 ms;
- 可扩展至 TB 级;
- JDK 23 默认。
ZGC 流程示意:
应用线程 ZGC线程 创建对象 染色引用 并发标记 并发搬迁 访问旧引用 通过读屏障重定向到新地址 应用线程 ZGC线程
四、对比与选型
GC 类型 | 停顿特性 | 压缩 | 并发性 | 典型场景 |
---|---|---|---|---|
Serial | 全停顿 | ✅ | ❌ | 单核、小内存 |
Parallel | 全停顿(多线程) | ✅ | ❌ | 吞吐优先型服务 |
CMS | 部分并发 | ❌ | ✅ | 老年代低延迟 |
G1 | 可控停顿 | ✅ | ✅ | 大堆服务,JDK9+ 默认 |
Shenandoah | 极低停顿 | ✅ | ✅ | 延迟敏感系统 |
ZGC | 极低停顿 | ✅ | ✅ | 超大堆、低延迟系统(JDK23 默认) |
五、可视化演进图
六、如何选择合适的 GC
应用类型 | 推荐 GC | 理由 |
---|---|---|
批处理 / 计算密集型 | Parallel GC | 吞吐最高 |
通用 Web 服务 | G1 | 稳定、停顿可控 |
低延迟接口 / 实时系统 | ZGC 或 Shenandoah | 延迟最低 |
内存 < 1 GB、单核环境 | Serial | 结构简单、低开销 |
七、写在最后
JVM GC 的演化史,本质上是计算机系统从"资源管理"向"响应时间控制"过渡的缩影。
从单线程清理,到分区并发,再到指针染色、实时搬迁,
HotSpot JVM 在每一个版本,都在降低开发者与内存管理之间的鸿沟。
在 JDK 23 时代,ZGC 已经能让堆规模达到 TB 级而停顿不足 10 ms。
这意味着 GC 不再是性能瓶颈,而是 JVM 自治系统的一部分。
作者注:
如需验证实际效果,可使用
-Xlog:gc*
开启详细 GC 日志;对于 JDK 23,推荐参数:
bashjava -XX:+UseZGC -Xmx32G -jar yourapp.jar
低延迟 GC 不等于高吞吐,选型仍需结合业务特点。
📘 延伸阅读
- JEP 333: ZGC: A Scalable Low-Latency Garbage Collector
- JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector
- JEP 473: Generational ZGC
- G1 GC Tuning Guide -- Oracle Docs
「理解 GC,不只是调优 JVM,更是理解计算机如何"呼吸"。」