从 JDK 8 到 JDK 23:HotSpot 垃圾回收器全景演进与深度剖析

作者:程序员小袁

关键词: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 默认)

五、可视化演进图

timeline title JVM GC 演进时间线 section 早期阶段 Serial/Parallel GC : JDK 1.2--8 section 过渡阶段 CMS : JDK 5--13 G1 GC 默认化 : JDK 9 section 新时代 ZGC(实验→稳定): JDK 11--15 Shenandoah:JDK 12 起 Generational ZGC 默认 : JDK 23

六、如何选择合适的 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,推荐参数:

    bash 复制代码
    java -XX:+UseZGC -Xmx32G -jar yourapp.jar
  • 低延迟 GC 不等于高吞吐,选型仍需结合业务特点。


📘 延伸阅读


「理解 GC,不只是调优 JVM,更是理解计算机如何"呼吸"。」

相关推荐
ha20428941944 小时前
Linux操作系统学习之---线程控制
java·linux·学习
清辞8534 小时前
C++入门(底层知识C与C++的不同)
开发语言·c++·算法
Knight_AL4 小时前
Spring AOP 中@annotation的两种写法详解
java·spring
fqbqrr4 小时前
2510C++,api设计原则,不除零
开发语言·c++
某空m4 小时前
【Android】BottomNavigationView实现底部导航栏
android·java
顾漂亮4 小时前
Spring AOP 实战案例+避坑指南
java·后端·spring
科比不来it4 小时前
Go语言数据竞争Data Race 问题怎么检测?怎么解决?
开发语言·c++·golang
biter down4 小时前
c语言14:字符指针
c语言·开发语言
SimonKing4 小时前
Mybatis-Plus的竞争对手来了,试试 MyBatis-Flex
java·后端·程序员