CPU过高排查
CPU飙高是线上最常见的事故之一。通常由死循环、死锁、GC频繁、正则回溯、大JSON序列化等原因导致。本文提供完整详细的排查流程,每一步都有具体命令、输出示例和解读。
一、排查总流程(5步法)
二、详细步骤演示(每条命令可复制执行)
第1步:定位高CPU进程
使用 top 命令查看所有进程,按CPU使用率排序,找到占用最高的进程。
关键判断:
- %CPU持续>90%:确认CPU飙高,需要排查
- load average超过CPU核数:系统过载,可能有大量线程在等待CPU
- 同时关注%MEM:如果内存也高,可能是GC频繁导致的CPU高
第2步:定位高CPU线程
找到进程后,用 top -Hp [PID] 查看该进程内所有线程的CPU使用情况。
判断要点:
- 如果只有一个线程CPU极高(95%+) → 死循环或复杂计算
- 如果多个线程CPU都高(各占30-50%) → 并发问题或GC线程
- 如果GC线程CPU高 → 内存不足,频繁GC
第3步:线程ID转16进制
jstack中线程的nid(native ID)是16进制显示的,需要将第2步拿到的十进制TID转为16进制。
得到16进制线程ID:0x3065(jstack中用这个值匹配)
第4步:jstack获取线程堆栈
最关键的一步!jstack打印JVM中所有线程的堆栈信息。通过16进制线程ID定位到具体的线程,查看它正在执行什么代码。
第5步:根据堆栈定位到代码
拿到堆栈信息后,打开对应的Java文件,定位到问题代码行,分析为什么导致CPU高。
三、Arthas快速定位(推荐,替代传统jstack)
Arthas是阿里开源的Java诊断神器。传统jstack需要多步操作,Arthas一条命令直接给出CPU最高的线程堆栈。强烈推荐在生产环境使用。
四、常见CPU飙高场景与解决方案
4.1 死循环
|
特征 |
解决 |
|---|---|
|
线程状态:RUNNABLE 堆栈:停在while(true)行 多次dump:堆栈完全不变 |
检查循环退出条件;加超时机制;循环体内加Thread.sleep/yield;使用有界队列+阻塞操作替代空转 |
4.2 死锁
|
特征 |
解决 |
|---|---|
|
线程状态:BLOCKED jstack末尾:Found 1 deadlock 多个线程互相等待对方的锁 |
统一加锁顺序;使用tryLock(timeout)替代lock();减小锁粒度;用jstack -l查看锁持有者 |
4.3 频繁GC(内存问题导致CPU高)
|
特征 |
解决 |
|---|---|
|
GC线程CPU占用高 jstat -gc 显示FGC持续增长 内存使用率接近100% |
jmap -histo查看对象分布→定位大对象;调大堆内存 -Xms -Xmx;排查内存泄漏(ThreadLocal没remove/静态集合无限增长) |
4.4 正则表达式回溯
4.5 HashMap并发死循环(JDK7)
JDK7中HashMap并发扩容时头插法导致环形链表,get操作进入死循环。堆栈停在HashMap.transfer()。解决:直接改用ConcurrentHashMap。
4.6 大JSON序列化/大对象创建
- 特征:堆栈停在Jackson/Gson/Fastjson序列化方法
- 原因:返回数据量过大(百万级记录)、循环引用、嵌套对象过深
- 解决:分页返回、@JsonIgnore忽略不必要字段、使用Streaming API逐条写、限制最大返回条数
五、完整排查命令速查表
|
命令 |
作用 |
|---|---|
|
top |
查看所有进程CPU使用率,找到高CPU进程 |
|
top -Hp [PID] |
查看进程内每个线程的CPU使用率 |
|
printf "%x\n" [TID] |
线程ID十进制→十六进制 |
|
jstack [PID] | grep [nid] -A 30 |
查看线程堆栈,定位问题代码 |
|
jstack -l [PID] |
查看线程堆栈+锁持有信息 |
|
jstat -gc [PID] 1000 |
每秒查看GC情况 |
|
jmap -histo:live [PID] |
查看内存对象分布 |
|
jmap -dump:live,file=xxx.hprof [PID] |
导出堆dump文件 |
|
Arthas: thread -n 3 |
一键看CPU最高的3个线程堆栈 |
|
Arthas: dashboard |
实时监控面板 |
|
Arthas: thread -b |
检测死锁 |
|
vmstat 1 10 |
系统级CPU/内存/IO监控 |
排查口诀:先 top 看进程 → top -Hp 看线程 → 转 16 进制 → jstack 拿堆栈 → 定位代码行 → Arthas 深入分析。传统方式5分钟定位,Arthas方式1分钟定位。