下面给你一套 生产环境可直接照抄执行的「Java CPU 飙升排查 & 解决全指南」。
不堆概念,全是实战步骤 ,适合你现在这种 多 Java 服务混布、CPU 突然飙高 的场景。
一、CPU 飙升的本质(先搞清方向)
Java 中 CPU 高 ≠ 一定是死循环
常见原因只有这几类:
| 类型 | 占比 |
|---|---|
| GC 频繁(最常见) | 40% |
| 死循环 / 计算密集 | 25% |
| 线程阻塞 + 自旋 | 15% |
| 锁竞争(synchronized / CAS) | 10% |
| 外部调用阻塞(Redis / DB / 下游) | 10% |
👉 先定位是哪一类,再谈解决
二、CPU 飙升排查标准流程(5 步)
✅ Step 1:找到"谁在吃 CPU"
top
记下 Java 进程 PID(比如 29968)
再看线程级:
top -Hp <PID>
你会看到:
- 某个线程 PID(TID)CPU 特别高(如 80%、90%)
✅ Step 2:把 TID 转成 16 进制(非常关键
printf "%x\n" <TID>
得到类似:
0x3f2a
✅ Step 3:看这个线程在干什么(90% 能定位)
jstack <PID> > jstack.log
然后搜索:
nid=0x3f2a
你会看到类似:
✅ 情况 1:GC 线程(最常见)
"GC task thread#0" os_prio=0 tid=... nid=0x3f2a runnable
👉 不是业务代码问题,是内存问题
✅ 情况 2:业务线程死循环
"http-nio-8080-exec-12" nid=0x3f2a runnable
at com.xxx.service.DeviceCache.lambda$update$1(DeviceCache.java:78)
👉 直接定位到代码行
✅ 情况 3:锁竞争
BLOCKED (on object monitor)
waiting for monitor entry
👉 锁粒度太大 / synchronized 滥用
✅ 情况 4:线程池堆积
WAITING (parking)
java.util.concurrent.LinkedBlockingQueue.take
👉 任务处理不过来
✅ Step 4:确认是不是 GC 导致的 CPU 高(必做)
jstat -gc <PID> 1000 5
重点看:
| 指标 | 危险信号 |
|---|---|
| FGC | 频繁 Full GC |
| FGCT | Full GC 时间很长 |
| OU | Old 区几乎满了 |
✅ 如果 GC 频繁 + CPU 高
👉 CPU 高是结果,内存泄漏是原因
✅ Step 5:看有没有"异常线程数"
jstack <PID> | grep java.lang.Thread | wc -l
| 线程数 | 说明 |
|---|---|
| < 300 | 正常 |
| 500~1000 | 偏高 |
| > 1500 | 高危 |
三、不同原因的解决方案(对症下药)
🔴 1️⃣ GC 导致 CPU 飙高(最常见)
✅ 解决步骤
1️⃣ 立刻加 JVM 参数:
-Xms2g
-Xmx2g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:MaxDirectMemorySize=512m
2️⃣ 抓堆:
jmap -dump:live,format=b,file=cpu_gc.hprof <PID>
3️⃣ 查:
-
静态 Map
-
本地缓存
-
大对象数组
🔴 2️⃣ 死循环 / 计算密集
✅ 典型代码
while(true) {
doSomething();
}
✅ 解决
-
加 sleep
-
加退出条件
-
改成定时任务(ScheduledExecutor)
🔴 3️⃣ 锁竞争导致 CPU 高
✅ 错误示例
synchronized(this) { ... }
✅ 优化
-
缩小锁范围
-
使用
ReentrantLock -
用并发容器(
ConcurrentHashMap)
🔴 4️⃣ 线程池失控
✅ 错误示例
Executors.newCachedThreadPool();
✅ 正确做法
new ThreadPoolExecutor(
10,
50,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadPoolExecutor.CallerRunsPolicy()
);
🔴 5️⃣ Redis / DB 慢导致 CPU 高
✅ 排查
-
Redis slowlog
-
MySQL slow query log
-
连接池耗尽
✅ 解决
-
加缓存
-
限流
-
异步化
四、线上应急处理清单(可直接用)
| 场景 | 操作 |
|---|---|
| CPU > 80% | top → 找 PID |
| 单核 CPU 100% | top -Hp → jstack |
| GC 导致 | 扩内存 / 重启 |
| 死循环 | 紧急回滚 |
| 线程爆炸 | 限流 / 降级 |
五、你当前环境的高危提示(结合前面)
结合你之前的 ps:
| 服务 | 风险 |
|---|---|
| vehicleGPSServer | ⚠️ 高 CPU + 小堆(极易 GC 飙 CPU) |
| deviceService | ⚠️ 无 -Xmx(GC 风险) |
| platformService | ⚠️ 平台级缓存风险 |
✅ 你现在遇到的 CPU 高,90% 是 GC 引起
六、一句话总结(记住这句)
Java CPU 飙升,90% 不是 CPU 的问题,而是内存 + 线程的问题。
如果你愿意,我可以帮你:
1️⃣ 对着你某个高 CPU PID 一步步在线定位
2️⃣ **解读 jstack / jstat 输出(你贴出来就行)**
3️⃣ 给你一份《Java 服务 CPU 飙高应急手册》
你只需要说: