1. CPU 飙高指标
CPU使用率
- 定义:CPU在单位时间内处于忙碌状态的时间占比(例如70%表示CPU有70%时间在运行任务,30%空闲)。
CPU负载
- 定义:单位时间内处于运行状态或等待CPU的进程数的平均值(如Linux中的1分钟、5分钟、15分钟负载)。
负载VS使用率
- 高使用率 + 高负载:CPU满负荷运行,任务无阻塞(如纯计算任务)。
- 低使用率 + 高负载:可能存在I/O阻塞(如磁盘读写导致进程等待,CPU空闲但任务堆积)。
- 多核系统:负载值需结合CPU核心数判断。例如:
- 4核CPU负载为4:满负荷;
- 负载为8:任务数是核心数的2倍,可能存在性能瓶颈。
CPU负载(CPU Load)和CPU使用率(CPU Utilization)是衡量系统性能的两个关键指标,它们既有区别又有联系,通常需要结合分析才能全面理解CPU的工作状态。
CPU指标查看 top
命令
top - 10:18:34 up 2:30, 1 user, load average: 0.56, 0.68, 0.63
任务: 414 total, 1 running, 413 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.9 us, 0.5 sy, 0.0 ni, 97.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 15725.1 total, 9377.8 free, 4159.5 used, 3410.3 buff/cache
MiB Swap: 4096.0 total, 4096.0 free, 0.0 used. 11565.7 avail Mem
-
load average
:1/5/15分钟的平均负载(参考值:≤ CPU核心数)。 -
running
:运行中的进程数(CPU繁忙的直接体现)。 -
zombie
:僵尸进程数(若不为0需排查)。 -
us
:用户态CPU时间(应用代码消耗)。 -
sy
:内核态CPU时间(系统调用消耗)。 -
id
:空闲CPU百分比。 -
wa
:I/O等待时间(高则可能磁盘瓶颈)。 -
其他命令和快捷键
top -p PID1,PID2
监控指定PID的进程top -u username
仅显示指定用户的进程Shift + P
按 CPU使用率 排序(默认)Shift + M
按 内存使用 排序Shift + T
按 进程运行时间 排序
2. Java线程导致CPU飙高排查
top
命令查看:发现 线程29354 进程CPU飙升
进程号 USER PR NI VIRT RES SHR %CPU %MEM TIME+ COMMAND 19323 wjx 20 0 6199220 1.7g 524144 S 120.9 11.2 7:06.38 idea 29354 wjx 20 0 7894264 40940 22540 S 100.3 0.3 3:00.07 java
top -Hp <PID>
查看指定进程的线程详情,发现线程 29355 线程CPU飙高
29355 wjx 20 0 7894264 40940 22540 R 99.9 0.3 6:48.10 java 29354 wjx 20 0 7894264 40940 22540 S 0.0 0.3 0:00.00 java 29356 wjx 20 0 7894264 40940 22540 S 0.0 0.3 0:00.00 GC task thread# 29357 wjx 20 0 7894264 40940 22540 S 0.0 0.3 0:00.00 GC task thread# 29358 wjx 20 0 7894264 40940 22540 S 0.0 0.3 0:00.00 GC task thread#
jstack <PID> > thread_29355_dump.txt
导出Java线程dump文件 ,然后根据内容查看哪里占用CPU
Full thread dump OpenJDK 64-Bit Server VM (25.452-b09 mixed mode):"DestroyJavaVM" #20 prio=5 os_prio=0 tid=0x000071169c011000 nid=0xae15 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Thread-0" #19 prio=5 os_prio=0 tid=0x000071169c98d000 nid=0xae48 runnable [0x000071167fffe000]java.lang.Thread.State: RUNNABLEat com.wangjunxin.ThreadTest.lambda$main$0(ThreadTest.java:19)at com.wangjunxin.ThreadTest$$Lambda$1/1942406066.run(Unknown Source)at java.lang.Thread.run(Thread.java:750)"Service Thread" #18 daemon prio=9 os_prio=0 tid=0x000071169c945800 nid=0xae46 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE
日志中nid 就是线程ID的16进制显示,可使用
printf '%x\n' 44616
来 输出线程ID 44616 的16进制是 ae48,可以确定导致CPU飙高的原因就是 Thread-0 线程导致。有些工具和网站也可以直接分析堆栈日志,提供更直观的可视化信息。如: https://gceasy.io/ft-index.jsp
3. 常见场景与解决方案
场景1:用户态CPU高
- 业务代码存在死循环或低效算法 -> 通过
perf/jstack
定位代码热点,优化算法或逻辑。 - 第三方库/框架的Bug(如日志库频繁压缩)。-> 升级有问题的库版本。
场景2:内核态CPU高
- 频繁系统调用(如短连接服务大量
accept()
)。-> 减少系统调用(如批量处理)。 - 文件系统操作(如小文件频繁
fsync
)。 -> 调整文件系统参数(如noatime
)。
场景3:CPU低但负载高
- I/O阻塞(如磁盘慢、数据库查询慢)。 -> 优化I/O(更换SSD、调整MySQL索引)。
- 大量进程等待调度(
vmstat
中r
队列长)。 -> 检查dmesg
是否有OOM或进程被杀记录。