主题
概念卡片:JVM 调优与问题排查
一句话机制
JVM 调优 = 用监控工具(jstat/jmap/jstack)观测 → 定位瓶颈(频繁 FGC / 内存泄漏 / 大对象)→ 用参数(堆大小/GC 选择/容器限制)调整;JIT 则是 JVM 自带的运行时优化(热点编译 + 方法内联 + 逃逸分析),多数场景无需手动干预。 调优的第一原则是「先观测、后动手」。
监控工具速查
| 工具 | 作用 |
|---|---|
| jps | 列出 JVM 进程 |
| jstat | 监视 GC/类装载/内存/JIT 运行数据 |
| jmap | 生成 heap dump、查看对象直方图 |
| jstack | 生成线程快照(查死锁/阻塞) |
| jinfo | 查看/调整运行参数 |
| jhat | 分析 dump(现已少用,多用 MAT) |
shell
jstat -gcutil -h20 pid 1000 # 看各区域使用率 + GC 频率
jmap -histo pid | head -n20 # 看存活对象按空间排序(定位大对象/泄漏)
jmap -dump:format=b,file=heap pid # dump 堆供 MAT 分析关键内存参数
| 参数 | 含义 | 建议 |
|---|---|---|
| -Xms / -Xmx | 堆初始/最大值 | 两者设相同,避免 GC 后重新分配 |
| -Xmn | 新生代大小 | 推荐堆的 3/8 |
| -Xss | 线程栈大小 | JDK5 起默认 1MB |
| -XX:NewRatio | 新生代:老年代 | 默认 2(新生代占 1/3) |
| -XX:SurvivorRatio | Eden:Survivor | 默认 8 |
| -XX:MaxTenuringThreshold | 晋升老年代年龄 | 默认 15 |
| -XX:MetaspaceSize/Max | 元空间 | JDK8 起,防 OOM |
GC 选择(按目标)
| 目标 | 参数 | 说明 |
|---|---|---|
| 吞吐量优先 | -XX:+UseParallelGC -XX:+UseParallelOldGC | 批处理/后台任务 |
| 响应时间优先 | -XX:+UseConcMarkSweepGC -XX:+UseParNewGC | 已废弃,JDK9 起换 G1 |
| 可预测停顿 | -XX:+UseG1GC(默认) | 互联网服务主流 |
容器环境(K8s 必配)
shell
-XX:+UseContainerSupport # 读取 cgroup 限制,超限抛 OOM 而非被 kill
-XX:MaxRAMPercentage=70.0 # 用容器内存的 70%(建议 ≤75%)
-XX:+HeapDumpOnOutOfMemoryError # OOM 自动 dump
-XX:HeapDumpPath=/path/dump.hprof容器化后不要用 -Xmx 写死绝对值,用 MaxRAMPercentage 让 JVM 感知 cgroup 限制,否则 JVM 可能无视容器限制、申请超过配额的内存被 OOM kill。
线上 FGC 排查
FGC 五大原因:大对象直接进老年代 · 内存泄漏 · 程序频繁生成长生命周期对象 · 显式 System.gc() · JVM 参数不合理。
排查流程:
- 看监控,了解 FGC 频率和触发时间
- 核对 JVM 参数(堆各区大小、收集器选型)是否合理
- 排除法:元空间打满?内存泄漏?显式 gc?
jmap -histo+ dump 定位可疑大对象/泄漏对象
内存占用过大排查(7 步)
1. K8s 找内存异常的 node
2. top -c 按 M 排序找进程 pid
3. ls /proc/pid/task | wc -l 看线程数
4. jmap -heap pid 看堆参数和占用
5. jmap -histo pid > file 打印各类实例数+内存
6. jmap -dump 转储堆
7. MAT 分析引用链定位泄漏源JIT 与编译优化
JIT 发现热点代码(计数器超阈值)后编译成机器码并缓存,还做这些优化:
- 方法内联:小方法直接嵌入调用处,省去方法调用开销(最重要的优化)
- 逃逸分析 → 栈上分配 / 标量替换 / 锁消除(详见 JVM技术栈总览)
- 锁膨胀、空值检查消除、类型检查消除、公共子表达式消除
不变量:JIT 优化是「运行时才发生的自动优化」,热点探测基于计数器;逃逸分析是 JIT 优化的关键一步,但 JIT 远不止逃逸分析。
常见误解(避坑)
- ❌ "调优就是无脑调大 -Xmx"。→ 内存泄漏场景调大只会延缓崩溃,先定位泄漏对象。
- ❌ "容器里用 -Xmx 设死就行"。→ 必须
UseContainerSupport+MaxRAMPercentage,否则 JVM 无视 cgroup 限制。 - ❌ "JIT 优化要手动开"。→ JIT 默认开启、自动触发,逃逸分析/方法内联都是自动的。
- ❌ "jmap -dump 可以随便在生产执行"。→ dump 会 STW 且文件巨大,生产慎用,优先用 jstat/histo 轻量观测。
关联
- 原始资料:7.JVM调优与线上问题排查 · 8. JIT优化
- 总览:JVM技术栈总览
- 相关卡:概念卡片:JVM垃圾回收GC(收集器选型是调优前提)
- 域地图:A00-百科/Java后端/Java后端