1068 字
约 3 分钟
6
S05-A01 · GC 收集器选型与调优
2024-12-31
2026-11-07

适用读者:要决定"用哪个 GC、堆给多大、调哪几个参数"的人。
前置:S05-J04。
实测环境:OpenJDK 21.0.12.1(G1 日志实测,2026-11-05)。
覆盖旧文:A-2315(1138) A-2634(552) A-2608(389) + 1016(100) 1011(86) 1018(82) 1132(167) 1951(136) 1624(142) 1025(83) 1625(137) 1637(90) 1626(155) 1007(67) 1020(74) = 3,398 点。
覆盖扩展:E-S05-015(收集器对比)、E-S05-016(GC 日志与停顿目标)。
上一篇:S05-J05 · 类加载与字节码执行
下一篇:S05-A02 · 线上故障诊断。


1. 一句话结论

选 GC 只有三个输入:堆多大、能容忍多长停顿、要不要极低延迟。 JDK 21 的默认答案(G1)能覆盖大多数场景。

收集器 算法 停顿 适合
Serial 复制/标记-压缩 长 小堆(< 数百 MB)、单核
Parallel 多线程复制 中 吞吐优先、批处理
CMS 并发标记清除 短 JDK 14 已移除(别再用)
G1(默认) Region 化 + 并发标记 可预测(MaxGCPauseMillis) 中大型堆(数 GB~数十 GB)
ZGC(21 生产可用) 染色指针 + 并发 亚毫秒级 超大堆、低延迟
Shenandoah 并发压缩 低 低延迟(非 Oracle 发行版常见)

2. 实测:G1 日志里的关键信号

实测输出(-Xmx128m -Xlog:gc):

[0.629s] GC(0) Pause Young (G1 Humongous Allocation) 56M->55M(128M) 14.651ms
[0.786s] GC(4) Pause Young (Prepare Mixed) 125M->65M(128M) 3.998ms
[0.845s] GC(5) Pause Young (Mixed) (Evacuation Failure) 125M->70M(128M) 5.213ms
信号 含义 要不要管
Humongous Allocation 大对象(> Region/2) 频繁 → 查是否有大数组
Evacuation Failure 晋升失败(目标区放不下) 必须管:会导致 Full GC
Pause Mixed 混合回收(含老年代) 频繁 → 老年代压力大
125M->65M(128M) 回收前后/上限 回收后接近上限 → 该加堆

判据:"回收后还剩多少"比"停顿多长"更重要——回收后接近上限说明堆不够。


3. 选型流程(E-S05-015)

堆 < 4GB?
├── 是 → 吞吐优先?→ Parallel;低延迟?→ G1
└── 否 → 停顿目标 < 10ms?
        ├── 是 → ZGC(21+)
        └── 否 → G1(设 -XX:MaxGCPauseMillis)
参数 作用 建议
-Xms/-Xmx 初始/最大堆 设成相同(避免动态扩堆抖动)
-XX:MaxGCPauseMillis G1 停顿目标 100–200ms 起步,别设太低(会导致频繁 Young GC)
-XX:ParallelGCThreads 并行线程数 默认按核数,容器里要手动限(避免超配)
-XX:+HeapDumpOnOutOfMemoryError OOM 时 dump 必开
-Xlog:gc*:file=... GC 日志 必开(带时间戳与文件轮转)

4. 三个常见调优误区(E-S05-016)

误区 后果
把 MaxGCPauseMillis 设成 10ms G1 只能缩小 Young 区 → 更频繁 GC,总吞吐下降
堆设得极大(64G+)却不换收集器 单次回收变长;ZGC/G1 大堆更合适
不设 ParallelGCThreads 跑在容器里 线程数按宿主机核数算 → 超配、抢占

判据:调参前先看"GC 频率"与"回收后占用"两个数,否则是在猜。


5. 迁移与回滚

变更 迁移 回滚
换 GC(G1→ZGC) 灰度一台 → 对比 P99 与 CPU → 全量 启动参数改回(无需改代码)
调堆大小 分批次,观察 GC 频率 参数回退
换 JDK 大版本 见 S04-A01 检查单 镜像回退

铁律:GC 参数变更必须"可回滚且可观测"——没有 GC 日志的变更等于盲调。


6. 自检(架构师版)

  1. 选 GC 的三个输入是什么?
  2. 为什么 CMS 不该再用?
  3. Evacuation Failure 意味着什么?怎么处理?
  4. 为什么 -Xms 与 -Xmx 要设成相同?
  5. MaxGCPauseMillis 设太低会怎样?

7. 下一篇

S05-A02 · 线上故障诊断:工具矩阵与 SOP

选型讲完,最后一篇讲"出事了怎么办":内存泄漏、CPU 飙高、频繁 Full GC 的三段式定界。


本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-2315/2634/2608/1016/1011/1018/1132/1951/1624/1025/1625/1637/1626/1007/1020;扩展点 E-S05-015/016。GC 日志为 OpenJDK 21 实测。

S05-A01 · GC 收集器选型与调优
https://www.clxhxhhr.top/posts/5252/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。