GC 性能指标/回收器发展/组合关系
GC 性能的两大核心指标
评价一个 GC 收集器的性能,主要看两个指标:
| 指标 | 说明 | 优化方向 |
|---|---|---|
| 吞吐量(Throughput) | 应用实际运行时间占总时间的比例 | 单位时间内处理的任务数量 |
| 停顿时间(Latency) | GC 暂停应用线程的时长 | 单次停顿和频率 |
总时间 = 应用运行时间 + GC 暂停时间
吞吐量 = 应用运行时间 / 总时间
如果 GC 停顿了 10 秒,总时间是 100 秒:
吞吐量 = 90 / 100 = 90%吞吐量 vs 停顿时间:鱼与熊掌
| 优化目标 | 侧重 | 场景 |
|---|---|---|
| 高吞吐量 | 最大化应用运行时间 | 批处理、数据计算 |
| 低延迟 | 最小化单次停顿 | Web 服务、实时交易 |
现实:吞吐量和停顿时间往往是对立的——高吞吐量意味着每次 GC 回收更多对象,但停顿时间可能更长。
GC 性能指标详解
1. 吞吐量
java
public class ThroughputDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < 1_000_000; i++) {
count += i;
}
long end = System.currentTimeMillis();
System.out.println("执行时间:" + (end - start) + " ms");
System.out.println("吞吐量:" + (end - start) / 1000.0 + " s");
}
}2. 停顿时间
bash
# 打印 GC 停顿时间
java -XX:+PrintGCDetails -XX:+PrintGCApplicationConcurrentTime MyApp
# GCApplicationConcurrentTime: 99987 ms
# → 99.987 秒内没有 GC3. 停顿频率
| GC 类型 | 停顿频率 | 说明 |
|---|---|---|
| MinorGC | 高(每分钟多次) | 年轻代满即触发 |
| FullGC | 低(每天几次) | 老年代满触发 |
| G1 MixedGC | 可控 | 可设置目标停顿时间 |
4. Footprint(内存占用)
GC 本身的内存开销:Remembered Set、Card Table、GC 日志缓冲等。
GC 收集器的发展历程
时间线:
1995 ──→ Java 1.0 ──→ Serial GC
│
2002 ──→ Java 1.4 ──→ Throughput GC(Parallel GC)
│
2006 ──→ Java 6 ──→ CMS GC(并发标记清除)
│
2012 ──→ Java 7 ──→ G1 GC
│
2017 ──→ Java 9 ──→ G1 成为默认 GC
│
2018 ──→ Java 11 ──→ ZGC(可扩展低延迟 GC)
│
2023 ──→ Java 21 ──→ ZGC 成为默认 GC七种经典 GC 收集器
| 收集器 | 年轻代 | 老年代 | 算法 | 停顿 | JDK 版本 |
|---|---|---|---|---|---|
| Serial | Serial | Serial Old | 复制 / 标记-压缩 | 长停顿 | 1.3+ |
| ParNew | ParNew | - | 复制 | 短停顿 | 1.4+ |
| Throughput(Parallel) | Parallel Scavenge | Parallel Old | 复制 / 标记-压缩 | 长停顿 | 1.4+ |
| CMS | ParNew | CMS | 复制 / 标记-清除 | 短停顿(并发) | 1.5+ |
| G1 | G1 | G1 | 复制 / 标记-清除 | 可预测停顿 | 7+ |
| ZGC | ZGC | ZGC | 着色指针 + 读屏障 | 亚毫秒 | 11+ |
| Shenandoah | Shenandoah | Shenandoah | 着色指针 + 转发指针 | 亚毫秒 | 12+ |
收集器组合关系
年轻代收集器 ──→ 老年代收集器(组合)
Serial ──────────────────→ Serial Old
│
ParNew ──────────────────→ CMS ──→ Serial Old(备选)
│
Throughput ──────────────→ Parallel Old
│
G1 ──────────────────────→ G1(独立管理年轻代和老年代)
│
ZGC ──────────────────────→ ZGC(统一管理)
│
Shenandoah ──────────────→ Shenandoah(独立管理)常见组合
bash
# 组合一:Serial(单线程,低配机器)
java -XX:+UseSerialGC MyApp
# 组合二:ParNew + CMS(低停顿,并发)
java -XX:+UseParNewGC -XX:+UseConcMarkSweepGC MyApp
# 组合三:Throughput/Parallel(高吞吐)
java -XX:+UseParallelGC MyApp
# 等价于:-XX:+UseParallelGC -XX:+UseParallelOldGC
# 组合四:G1(平衡,JDK 9+ 默认)
java -XX:+UseG1GC MyApp
# 组合五:ZGC(超低延迟)
java -XX:+UseZGC MyApp
# 组合六:Shenandoah(低延迟)
java -XX:+UseShenandoahGC MyApp各收集器的适用场景
| 场景 | 推荐收集器 | 原因 |
|---|---|---|
| 单核 CPU / 低配机器 | Serial | 没有线程切换开销 |
| 批处理 / 离线计算 | Throughput(Parallel) | 高吞吐量优先 |
| Web 服务 / 在线交易 | G1 / ZGC | 低延迟优先 |
| 大堆(> 32GB) | ZGC / G1 | ZGC 不受堆大小影响 |
| 容器 / K8s | G1 / ZGC | 内存可控,停顿可预测 |
| JDK 11+ 新项目 | ZGC | 最佳延迟性能 |
| JDK 21+ 新项目 | ZGC(默认) | JDK 21 默认 GC |
收集器与代际关系的特殊说明
ParNew 和 Serial 的关系
- Serial:年轻代 Serial = Serial Old
- ParNew:年轻代并行(多线程版本)= Serial Old
- ParNew 不能和 Throughput(Parallel Scavenge)组合
CMS 的退位
CMS 是 JDK 14 中正式移除的收集器(JDK 9 已标记废弃)。如果还在使用 CMS,建议迁移到 G1 或 ZGC。
G1 的统一管理
G1 不再严格区分年轻代和老年代,而是把整个堆分成多个 Region,动态调整各类型 Region 的数量。
本节小结
GC 性能指标与收集器概览:
| 指标 | 含义 | 优化方向 |
|---|---|---|
| 吞吐量 | 应用运行时间 / 总时间 | 高吞吐:Parallel GC |
| 停顿时间 | GC 暂停的时长 | 低延迟:G1/ZGC |
| 停顿频率 | GC 发生的频率 | 分代收集减少 FullGC |
收集器选择原则:
- 低配/单核:Serial
- 高吞吐批处理:Throughput/Parallel
- 低延迟服务:G1 或 ZGC
- JDK 11+:ZGC
- JDK 21+:ZGC(默认)
下一节,我们来看 Serial/Serial Old 回收器。
