JVM调优方法论
JVM 调优不是参数游戏,而是一个观测、假设、验证的工程过程。没有目标和证据的调优,很容易把系统调得更复杂。
# 1. 先定义目标
调优前先明确目标:
- 降低 P99 延迟。
- 提高吞吐量。
- 降低内存占用。
- 减少 Full GC。
- 缩短启动时间。
- 支撑更高并发。
不同目标可能互相冲突。例如更大的堆可能减少 GC 频率,但增加单次停顿风险。
# 2. 建立基线
先记录当前状态:
- QPS。
- RT。
- CPU。
- 堆使用。
- GC 次数和停顿。
- 线程数。
- 错误率。
- JVM 参数。
- JDK 版本。
没有基线,就无法判断优化是否有效。
# 3. 收集证据
常用证据:
- GC 日志。
- 线程 dump。
- 堆 dump。
- JFR。
- APM 指标。
- 业务日志。
- 系统指标。
不要只依赖单一工具。复杂问题往往需要多维度关联。
# 4. 一次只改一个变量
调优时尽量一次只改一个关键变量。
错误做法:
同时改堆、GC、线程池、缓存、数据库连接池
这样即使问题改善,也不知道是哪一个改动有效。
# 5. 优先优化业务和对象分配
很多 JVM 问题不是 JVM 参数导致的,而是业务代码导致的:
- 一次性加载大文件。
- 大对象频繁创建。
- 缓存无上限。
- JSON 反复序列化。
- 线程池无界队列。
- SQL 查询返回过多数据。
先优化对象生命周期和资源使用,再考虑 JVM 参数。
# 6. 选择合适 GC
普通服务端应用:
- 现代 JDK 默认 G1 通常是合理起点。
高吞吐批处理:
- 可以评估 Parallel GC。
低延迟大堆:
- 可以评估 ZGC 或 Shenandoah。
选择 GC 后必须压测验证,而不是只看理论。
# 7. 压测和回归
调优结果要通过压测验证:
- 正常流量。
- 峰值流量。
- 突刺流量。
- 长时间稳定性。
- 故障降级场景。
同时要观察是否引入新的问题。
# 8. 阶段小结
JVM 调优的正确顺序是:定义目标、建立基线、收集证据、提出假设、小步修改、压测验证、持续观察。优秀的调优不是参数背得多,而是能把问题定位清楚,把改动控制得足够小。
# 9. 调优闭环图
定义目标
│
▼
建立基线
│
▼
采集证据
│
▼
提出假设
│
▼
小步修改
│
▼
压测验证
│
├─ 有效 -> 灰度上线 -> 持续观察
└─ 无效 -> 回滚 -> 重新假设
调优一定要可回滚。一次改太多参数,出了问题很难定位是哪一个改动引入的。
# 10. 调优案例模板
记录一次 JVM 调优建议包含:
| 项目 | 示例 |
|---|---|
| 问题 | P99 从 80ms 抖到 800ms |
| 目标 | P99 控制在 150ms 内 |
| 证据 | GC 日志显示 G1 Full GC,老年代回收后下降少 |
| 假设 | 本地缓存无上限导致老年代占满 |
| 改动 | 增加缓存最大容量和过期策略 |
| 验证 | 压测 2 小时,Full GC 消失,P99 稳定 |
| 风险 | 缓存命中率下降 |
| 回滚 | 恢复原缓存配置 |
# 11. Tips 快问快答
Q:JVM 调优优先调应用还是参数?
A:优先看应用对象分配、缓存、线程池、IO 等。参数是辅助手段。
Q:没有压测能不能调优?
A:可以做紧急止血,但长期修复必须验证。否则只是换一种风险。
Q:调优成功的标准是什么?
A:达成事先定义的业务指标,并且没有引入新的稳定性问题。
Q:为什么一次只改一个变量?
A:为了知道哪个改动产生了效果,便于回滚和复盘。
上次更新: 2026/06/24, 16:03:01