线上CPU飙高:原因+排查流程+面试标准回答(Java后端通用,直接背)
一、常见CPU飙高原因(分大类,面试必答)
1. 代码层面(最常见)
- 死循环/循环逻辑异常:
while(true)、递归无终止条件、遍历逻辑死循环 - 频繁GC(Full GC/YGC频繁):内存泄漏、对象创建过多、大对象、内存溢出
- 密集计算:大数据量循环、复杂正则、加密/解析、序列化、数学运算
- 锁竞争激烈:自旋锁、synchronized/ReentrantLock 大量等待,线程空转
- 线程池滥用:线程无限创建、任务堆积、线程死循环执行任务
- IO阻塞假象:少量IO阻塞+大量重试/轮询,导致CPU空跑
2. 框架/中间件层面
- 定时任务扎堆执行、任务并发过高
- 连接池耗尽,线程反复重试获取连接
- 第三方SDK/中间件Bug、轮询心跳异常
- 日志狂打(错误日志刷屏、异步日志阻塞)
3. 系统/运维层面
- 服务器被其他进程抢占CPU
- 病毒、挖矿程序、恶意脚本
- 内核/驱动、虚拟化环境异常
二、标准排查流程(线上实操步骤,面试按顺序说)
步骤1:服务器全局定位(Linux)
top:查看整机CPU、负载,找到CPU占比最高的进程PIDshift + P按CPU排序,记录高CPU PID
步骤2:定位进程内高消耗线程
top -Hp 进程PID:查看该进程下所有线程,按CPU排序,记录线程TID(十进制)printf "%x\n 十进制TID":转成十六进制(jstack用)
步骤3:抓取线程栈,定位代码行
jstack 进程PID | grep 十六进制TID -A 20- 查看线程栈:
- 卡在循环/业务代码 → 代码死循环/密集计算
- 卡在锁/
park→ 锁竞争、死锁 - 大量线程处于
RUNNABLE且在GC相关方法 → GC问题
步骤4:如果是GC导致CPU高(高频场景)
jstat -gc 进程PID 1000每秒看GC次数、耗时jmap -dump:format=b,file=xxx.hprof 进程PID导出堆快照- 用MAT/VisualVM分析:内存泄漏、大对象、重复创建对象
步骤5:辅助验证
- 查看监控面板:接口QPS、耗时、报错量、定时任务、慢日志
- 查看系统日志:报错刷屏、死循环日志、异常重试
- 临时处理:重启、限流、关停异常定时任务、切流量止损
三、面试满分回答(分「简答版」「详细版」,按需选用)
👉 简答版(一面/快速提问,1分钟说完)
线上CPU飙高主要分为代码逻辑、GC、锁竞争、中间件/运维四类。
排查先通过top找到高CPU进程,再用top -Hp定位高消耗线程,转十六进制后用jstack查看线程栈定位代码;如果是GC频繁导致,就用jstat观察GC情况,jmap导出堆文件用MAT分析内存问题,同时结合监控、日志、定时任务综合排查,先止损再修复代码。
👉 详细版(二面/架构岗,完整流程,2–3分钟)
我梳理下线上CPU飙高的原因和完整排查思路:
常见原因
第一类是业务代码问题:死循环、递归无退出、密集计算、频繁创建对象;
第二类是GC异常:内存泄漏、频繁Full GC/YGC,GC线程占用大量CPU;
第三类是并发问题:锁竞争、线程池不合理、线程空转;
还有定时任务扎堆、日志刷屏、第三方组件或服务器进程抢占资源也会导致。排查流程(线上标准流程)
① 先用top命令查看整机状态,定位CPU占用最高的Java进程PID;
② 执行top -Hp PID查看进程内线程,找到CPU最高的线程ID,转为十六进制;
③ 使用jstack PID结合十六进制线程ID,打印线程堆栈,直接定位到具体代码行:- 栈卡在业务循环处:判断死循环/密集计算;
- 大量线程阻塞在锁相关代码:锁竞争或死锁;
- 线程卡在GC模块:判定GC导致CPU高。
④ 若为GC问题:用jstat持续观测GC频率与耗时,jmap导出堆快照,通过MAT分析内存泄漏、大对象、无效对象。
⑤ 最后结合应用监控、接口日志、定时任务、中间件状态交叉验证,线上优先限流、重启、关停异常任务止损,再修复代码。
优化方向
修复死循环、简化密集计算、优化对象创建避免内存泄漏、合理配置线程池与锁、错峰执行定时任务。
四、高频追问&应答
问:怎么区分是代码死循环还是GC导致CPU高?
答:jstack看线程栈,业务线程卡在业务代码就是死循环/计算;大量线程栈在GC相关方法、且jstat看到GC频繁,就是GC问题。问:线上能频繁jmap dump吗?
答:不建议,dump会暂停应用(STW),线上优先先抓jstack,低峰期再dump,或使用在线分析工具。问:遇到CPU100%紧急处理步骤?
答:先止损:限流、摘除节点、重启实例;再保留现场(抓jstack、日志),最后排查根因修复。