Skip to content

概念卡片: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:SurvivorRatioEden: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 参数不合理。

排查流程:

  1. 看监控,了解 FGC 频率和触发时间
  2. 核对 JVM 参数(堆各区大小、收集器选型)是否合理
  3. 排除法:元空间打满?内存泄漏?显式 gc?
  4. 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 远不止逃逸分析。

常见误解(避坑)

  1. ❌ "调优就是无脑调大 -Xmx"。→ 内存泄漏场景调大只会延缓崩溃,先定位泄漏对象。
  2. ❌ "容器里用 -Xmx 设死就行"。→ 必须 UseContainerSupport + MaxRAMPercentage,否则 JVM 无视 cgroup 限制。
  3. ❌ "JIT 优化要手动开"。→ JIT 默认开启、自动触发,逃逸分析/方法内联都是自动的。
  4. ❌ "jmap -dump 可以随便在生产执行"。→ dump 会 STW 且文件巨大,生产慎用,优先用 jstat/histo 轻量观测。

关联

最近更新