JVM问题排查
一、明确问题现象
- 常见问题类型:
- 内存溢出(
OutOfMemoryError
) - CPU占用率飙升(100%)
- 线程阻塞/死锁(应用无响应)
- GC频繁(应用卡顿)
- 类加载异常(
ClassNotFoundException
/NoClassDefFoundError
)
- 内存溢出(
二、基础信息收集
1. 查看JVM参数
1 | jps -lvm # 列出所有Java进程及其启动参数 |
关键参数:堆大小(-Xms
, -Xmx
)、GC算法(-XX:+UseG1GC
)、OOM行为(-XX:+HeapDumpOnOutOfMemoryError
)
2. 实时监控
1 | jstat -gcutil <pid> 1000 # 每秒打印一次GC情况 |
输出关键指标:
YGC/YGCT
:Young GC次数/耗时FGC/FGCT
:Full GC次数/耗时O
:老年代使用率M
:元空间使用率
三、深度排查工具
1. 内存问题排查
堆内存分析:
1
2jmap -dump:format=b,file=heap.hprof <pid> # 生成堆转储文件
jmap -histo:live <pid> | head -20 # 查看存活对象统计(生产慎用!)分析工具:
- Eclipse MAT:分析内存泄漏(Dominator Tree查找大对象)
- VisualVM:实时堆内存监控
Native内存泄漏:
1
pmap -x <pid> | sort -n -k3 # 查看进程物理内存分布
2. CPU占用高排查
- 定位高CPU线程:
1
2top -H -p <pid> # 查看进程内线程CPU占用
printf "%x\n" <tid> # 将线程ID转为16进制 - 抓取线程栈:
1
jstack <pid> > thread_dump.txt
- 分析:
- 查找对应16进制线程ID的栈信息
- 关注
RUNNABLE
状态的线程(尤其是长时间运行的代码)
3. 线程阻塞/死锁
1 | jstack <pid> | grep -A 10 "BLOCKED" # 查找阻塞线程 |
典型场景:锁竞争、I/O阻塞、数据库连接池耗尽
4. GC问题排查
- 开启GC日志(启动参数):
1
-Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
- 分析工具:
- GCeasy:在线分析GC日志
- G1GC推荐添加:
-XX:+PrintTenuringDistribution
(查看晋升详情)
常见GC问题:
- Full GC频繁:老年代空间不足 / 元空间溢出
- Young GC时间长:新生代过大 / 对象晋升过快
四、高级诊断工具
Arthas(阿里开源) - 动态诊断神器
1
2
3
4
5# 追踪方法调用耗时
trace com.example.Service *methodName
# 监控方法执行统计
monitor -c 5 com.example.Service *methodNameAsync-Profiler - 低开销性能分析
1
./profiler.sh -d 60 -f flamegraph.html <pid> # 生成CPU火焰图
JDK Mission Control - 官方性能分析套件
- 安全点分析、JFR(Java Flight Recorder)录制
五、常见问题速查表
问题现象 | 优先检查项 |
---|---|
OOM | 堆转储分析 + MAT Dominator Tree |
CPU 100% | jstack 定位线程 + 火焰图 |
应用卡顿 | GC日志分析(是否GC导致STW) |
线程数暴涨 | jstack 统计线程状态 + 线程池配置 |
请求延迟高 | 链路追踪 + 数据库慢查询 |
六、预防性建议
- 监控先行:
- Prometheus + Grafana监控:JVM内存、GC次数、线程池状态
- 添加APM工具(SkyWalking, Pinpoint)
- 参数调优:
- 根据压测结果设置堆大小(避免默认值)
- G1GC推荐:
-XX:MaxGCPauseMillis=200
- 代码规范:
- 避免大对象(如
byte[100MB]
) - 及时关闭资源(数据库连接、文件流)
- 避免大对象(如
关键原则:通过堆转储和线程栈能解决80%问题,复杂场景结合Profiler工具深入分析。生产环境避免直接使用
jmap -histo:live
(可能触发Full GC)!
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 技术之路!
评论