垃圾收集器分类:年轻代 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:+UseSerialGC | Serial | Serial Old | 停顿长 | 客户端、小型应用 |
-XX:+UseParNewGC | ParNew | Serial Old | 多线程并行 | JDK 8(已移除) |
-XX:+UseConcMarkSweepGC | ParNew | CMS | 并发收集 | 低延迟(JDK 8) |
-XX:+UseParallelGC | Parallel Scavenge | Parallel Old | 吞吐量优先 | 后台计算 |
-XX:+UseG1GC | G1 | G1 | 可预测停顿 | JDK 9+ 通用 |
-XX:+UseZGC | ZGC | ZGC | < 1ms 停顿 | JDK 11+ 低延迟 |
-XX:+UseShenandoahGC | Shenandoah | Shenandoah | 并发回收 | 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 参数?
