Skip to content

垃圾收集器分类:年轻代 vs 老年代收集器全景图

JVM 提供了多种垃圾收集器,就像一个「清洁团队」,每个成员负责不同的区域。

它们之间可以自由组合,形成不同的「清洁方案」。


收集器一览

┌─────────────────────────────────────────────────────────────────────┐
│                        JVM 垃圾收集器家族                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   年轻代收集器                                                      │
│   ┌──────────────┬──────────────┬──────────────────────┐             │
│   │    Serial    │    ParNew    │   Parallel Scavenge │             │
│   │  单线程      │  多线程      │   吞吐量优先        │             │
│   └──────────────┴──────────────┴──────────────────────┘             │
│           │              │                   │                       │
│           └──────────────┴───────────────┬───┘                       │
│                                          │                           │
│                                          ▼                           │
│                               ┌─────────────────┐                    │
│                               │   组合关系       │                    │
│                               └─────────────────┘                    │
│                                          │                           │
│           ┌──────────────────────────────┴──────────────────────────┐ │
│           │                         老年代收集器                   │ │
│   ┌───────┴───────┬─────────────────┬─────────────────┬─────────┐ │
│   │  Serial Old   │  Parallel Old    │      CMS        │   G1    │ │
│   │  单线程整理   │  多线程整理      │  并发标记清除    │  Region │ │
│   └───────────────┴─────────────────┴─────────────────┴─────────┘ │
│                                                                      │
│   低延迟收集器(JDK 11+)                                           │
│   ┌──────────────────┬──────────────────┐                            │
│   │       ZGC        │   Shenandoah    │                            │
│   │  < 1ms 停顿      │  并发回收        │                            │
│   └──────────────────┴──────────────────┘                            │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

年轻代收集器

Serial:最简单最古老

  • 单线程执行
  • Stop The World
  • 复制算法
  • 适用于客户端模式(-client)或小型应用

ParNew:Serial 的多线程版

  • 多线程并行执行
  • Stop The World
  • 复制算法
  • CMS 的默认年轻代收集器

Parallel Scavenge:吞吐量优先

  • 多线程并行执行
  • Stop The World
  • 复制算法
  • 吞吐量优先,适合后台计算任务
  • 支持自适应调节(-XX:+UseAdaptiveSizePolicy

老年代收集器

Serial Old:老年代的单线程收集器

  • 单线程执行
  • Stop The World
  • 标记-整理算法
  • 作为 CMS 的备用收集器

Parallel Old:吞吐量优先的老年代收集器

  • 多线程并行执行
  • Stop The World
  • 标记-整理算法
  • 与 Parallel Scavenge 配合,组成「吞吐量优先」组合

CMS:并发标记-清除

  • 并发收集,大部分时间与应用并发执行
  • 标记-清除算法(有碎片)
  • JDK 8 常用的低延迟收集器
  • JDK 14 被移除

G1:Region 化收集器

  • ** Region 化的分代收集器
  • 整体标记-整理,局部复制
  • JDK 9+ 默认收集器
  • 可预测的停顿时间

收集器组合关系

不是所有收集器都能随意组合:

┌─────────────────────────────────────────────────────────────────────┐
│                    收集器组合关系图                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   年轻代                        老年代                                │
│   ┌─────────┐                 ┌─────────┐                           │
│   │ Serial  │ ─────────────► │Serial Old│ ✓                       │
│   └─────────┘                 └─────────┘                           │
│                                                                      │
│   ┌─────────┐                 ┌─────────┐                           │
│   │ ParNew  │ ─────────────► │  CMS   │ ✓(JDK 8)                 │
│   └─────────┘                 └─────────┘                           │
│         │                            │                              │
│         │                            │                              │
│         │                     ┌─────────────┐                        │
│         └───────────────────► │Serial Old  │ ✓(CMS 失败时的备用)   │
│                               └─────────────┘                        │
│                                                                      │
│   ┌───────────────────┐         ┌───────────────────┐               │
│   │ Parallel Scavenge│ ──────► │ Parallel Old      │ ✓            │
│   └───────────────────┘         └───────────────────┘               │
│                                                                      │
│   ┌───────────────────┐         ┌───────────────────┐               │
│   │       G1          │ ──────► │       G1          │ ✓(统一)     │
│   └───────────────────┘         └───────────────────┘               │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

✗ 组合:ParNew + Parallel Old(JDK 8 已移除)
✗ 组合:Serial + CMS

各组合适用场景

组合年轻代老年代特点适用场景
-XX:+UseSerialGCSerialSerial Old停顿长客户端、小型应用
-XX:+UseParNewGCParNewSerial Old多线程并行JDK 8(已移除)
-XX:+UseConcMarkSweepGCParNewCMS并发收集低延迟(JDK 8)
-XX:+UseParallelGCParallel ScavengeParallel Old吞吐量优先后台计算
-XX:+UseG1GCG1G1可预测停顿JDK 9+ 通用
-XX:+UseZGCZGCZGC< 1ms 停顿JDK 11+ 低延迟
-XX:+UseShenandoahGCShenandoahShenandoah并发回收JDK 12+ 低延迟

默认收集器

bash
# 查看默认收集器
java -XX:+PrintCommandLineFlags -version

# JDK 7/8(非 G1):Parallel Scavenge + Parallel Old
# JDK 9+:G1

如何选择收集器

选择原则

┌─────────────────────────────────────────────────────────────┐
│                     收集器选择决策树                        │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  你的应用特点是什么?                                        │
│       │                                                     │
│  ┌────┴────┬────────────┐                                  │
│  ▼         ▼            ▼                                    │
│ 低延迟    高吞吐      通用                                    │
│ 需求      需求                                             │
│  │         │            │                                    │
│  ▼         ▼            ▼                                    │
│ ZGC       Parallel    G1                                    │
│ /G1       Scavenge    (JDK 9+)                              │
│           /Old                                          │
│                                                              │
└─────────────────────────────────────────────────────────────┘

实战配置示例

bash
# 场景 1:高并发 API 服务(低延迟优先)
java -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:G1HeapRegionSize=4m \
     -Xmx4g your.Application

# 场景 2:后台批处理(高吞吐优先)
java -XX:+UseParallelGC \
     -XX:+UseParallelOldGC \
     -XX:GCTimeRatio=19 \
     -XX:MaxGCPauseMillis=500 \
     -Xmx8g your.Application

# 场景 3:超低延迟(JDK 11+)
java -XX:+UseZGC \
     -XX:+ZGenerational \
     -Xmx16g your.Application

面试追问方向

  • Serial 和 ParNew 都是单线程,为什么 ParNew 更快?
  • CMS 和 G1 都是并发收集器,它们的核心区别是什么?
  • 什么是「并发模式失败」(Concurrent Mode Failure)?如何避免?
  • ZGC 声称停顿时间 < 1ms,它是怎么做到的?代价是什么?
  • 如果线上延迟很高,但 CPU 使用率不高,应该调整哪些 GC 参数?

基于 VitePress 构建