← 返回文章
JavaJVMGC 2026-05-12 10:00 5 min read

Java 垃圾回收策略概览

从 Parallel GC 到 ZGC,梳理 JDK 各版本默认 GC 及其核心思路,帮你快速建立 JVM 垃圾回收的整体认知。

为什么需要垃圾回收?

Java 把内存管理交给 JVM,开发者不需要手动 free()。 JVM 的垃圾回收器(GC)负责找出不再被引用的对象并释放它们占用的堆内存。 不同的 GC 在吞吐量(单位时间处理量)和停顿时间(Stop-The-World,STW)之间取舍不同, 随着 JDK 迭代,默认 GC 也在不断演进。

Parallel GC — JDK 7 / 8 默认

通过 -XX:+UseParallelGC 开启,JDK 7 和 JDK 8 均默认使用。

核心思路:

  • 多线程并行执行——充分利用多核 CPU,大幅缩短 GC 时间(相比早期单线程的 Serial GC)。
  • 年轻代:复制算法(Copying)——将存活对象从 Eden / Survivor 复制到另一块 Survivor,整理后无碎片。
  • 老年代:标记-压缩(Mark-Sweep-Compact)——标记存活对象,清除死亡对象,再将存活对象紧凑排列消除碎片。
  • 全程 STW——GC 期间所有业务线程暂停,停顿时间随堆大小线性增长,不适合对延迟敏感的场景。

适合批处理、后台计算等吞吐量优先、能容忍短暂停顿的应用。

CMS — 低停顿先行者(JDK 8)

Concurrent Mark Sweep,通过 -XX:+UseConcMarkSweepGC 在 JDK 8 中开启。 JDK 9 起标记为废弃(deprecated),JDK 14 正式移除。

核心思路:

  • 老年代并发标记——大部分标记工作与业务线程并发执行,大幅减少停顿时间。
  • 只有两个短暂 STW 阶段——初始标记(Initial Mark)和重新标记(Remark),耗时极短。
  • 标记-清除,不压缩——不移动对象,因此会产生内存碎片,长时间运行后可能触发一次全量 STW 压缩(Serial Full GC)。
  • CPU 占用较高——并发阶段与业务线程竞争 CPU,在核数少的机器上影响吞吐量。

适合对响应时间敏感、堆不超大(通常 < 4 GB)的 Web 服务。

G1 GC — JDK 9+ 默认

Garbage-First,从 JDK 9 起成为默认 GC,通过 -XX:+UseG1GC 显式指定。

核心思路:

  • Region 分区——把堆划分为大量等大的 Region(默认 1–32 MB),不再严格区分连续的年轻代 / 老年代区域,每个 Region 可动态承担不同角色。
  • 优先回收垃圾最多的 Region——"Garbage First" 由此得名,有限的 GC 时间用在收益最大的地方。
  • 可预测停顿目标——通过 -XX:MaxGCPauseMillis 设置期望停顿(默认 200ms),G1 自动调节每次回收的 Region 数量。
  • 兼顾吞吐与延迟——在大堆(4–32 GB)场景下比 CMS 更稳定,也比 Parallel GC 停顿更短,是当前最通用的选择。

ZGC — 超低延迟(JDK 15+ 正式可用)

通过 -XX:+UseZGC 开启,JDK 21 起成为许多低延迟场景的首选。

核心思路:

  • 几乎全程并发——标记、重定位、引用处理均与业务线程并发,STW 只剩极短的初始标记和转移阶段。
  • 停顿时间 < 1ms——且基本不随堆大小增长,在数百 GB 大堆下依然保持毫秒级停顿。
  • 染色指针(Colored Pointers)——利用 64 位指针的高位存储 GC 元数据,避免额外的内存开销和读屏障复杂度。
  • 吞吐量略低——并发线程与业务线程共享 CPU,总体吞吐量不如 Parallel GC,但对延迟敏感应用来说这个代价值得。

适合实时交易、游戏服务器、大内存微服务等对毫秒级延迟有严格要求的场景。

横向对比

GC 默认版本 停顿 吞吐量 适用场景
Parallel GC JDK 7 / 8 高(全 STW) ★★★★★ 批处理、计算密集
CMS JDK 8 可选 ★★★☆☆ 低延迟 Web(已废弃)
G1 GC JDK 9+ 中(可预测) ★★★★☆ 通用、大堆服务
ZGC JDK 15+ 极低(<1ms) ★★★☆☆ 超低延迟、超大堆

没有银弹——选对 GC 取决于你的堆大小、业务延迟要求和 JDK 版本。 大多数现代服务跑在 JDK 17 / 21 上,G1 GC 是最稳妥的起点, 如果 P99 延迟仍不达标,再考虑切换到 ZGC。