top 显示 load average 12.5——这个数粗略代表”平均有多少个任务在抢 CPU 或者排队等资源”,越大说明机器越忙,12.5 看着已经很吓人了;可 CPU 使用率却只有 30%,这台机器到底是忙还是闲?free 显示 free 列只剩几百 M,服务却跑得好好的——内存到底够不够?监控命令谁都会敲,但输出里的指标读不懂,跑了也白跑。

这是 Linux 命令系列的一篇,承接 Linux 常见命令与工具地图服务器排查那篇 给了 ps/top/free 的基本用法,这篇专讲输出怎么读懂。

ps aux 的 STAT 列:进程现在处于什么状态

ps aux 输出里的 STAT 列是最有信息量、也最少人看懂的一列。第一个字符是进程的主状态,就五种:

1
2
3
4
5
6
7
R    运行中或在运行队列里排队等 CPU
S 可中断睡眠——在等某个事件(网络数据、锁、定时器),绝大多数进程平时都是这个状态
D 不可中断睡眠——通常是卡在磁盘 IO 上;这个状态的进程不响应任何信号,
连 kill -9 都杀不动,只能等 IO 完成或者重启机器
Z 僵尸进程——已经退出了,但父进程还没回收它的退出状态;
杀僵尸本身没用(它已经死了),要处理的是它的父进程
T 被暂停(收到 SIGTSTP/SIGSTOP,比如按了 Ctrl-Z)

主状态后面可能还挂着几个后缀,常见的有这些:

1
2
3
4
5
6
s    会话首进程(session leader)
l 多线程进程
+ 在前台进程组(占着终端)
< 高优先级(nice 值为负,抢 CPU 更凶)
N 低优先级(nice 值为正,会让着别的进程)
L 有内存页被锁定在物理内存里,不允许换出(数据库进程常见)

比如 Ss 读作”睡眠中的会话首进程”(守护进程的典型状态),R+ 读作”正在前台运行”,S< 读作”睡眠中的高优先级进程”。<N 这两个后缀对应的 nice 优先级机制,在 kill 信号那篇 的 nice/renice 部分讲过。

排查时有两个状态要特别敏感:一堆进程卡在 D 状态,基本可以断定磁盘 IO 出了问题(盘太慢、NFS 挂了);Z 状态零星一两个无害,大量出现说明父进程的代码有 bug(没有 wait 子进程)。kill 对这两种状态都无能为力,原因在 kill 信号那篇 讲过——D 状态不响应信号,Z 已经死了没什么可杀的。

VSZ 和 RSS:两个”内存占用”差在哪

还是看 ps aux 的输出——STAT 前面还有两列跟内存相关的数字,VSZ 和 RSS,多数人从来没细看过它们的区别:

1
2
USER    PID  %CPU  %MEM     VSZ    RSS  ...  COMMAND
root 12345 15.2 8.4 2150432 342012 ... java -jar app.jar
  • VSZ(Virtual Set Size):进程的虚拟地址空间总大小,包括映射了但从没真正用过的内存、共享库等,通常大得吓人且没什么诊断价值
  • RSS(Resident Set Size):进程实际占用的物理内存

两列的单位都是 KiB(1024 字节)——上面这行的 VSZ 2150432 KiB 约等于 2.05 GiB,RSS 342012 KiB 约 334 MiB。ps 不会帮你换算成人类可读单位,位数多的时候自己心算除两次 1024。

看一个进程”到底吃了多少内存”、判断有没有内存泄漏,盯 RSS——它持续上涨才是真的在吃内存;VSZ 大不代表任何问题。

load average:三个数字和核数一起看

top 第一行和 uptime 都会显示 load average,三个数字分别是最近 1 分钟、5 分钟、15 分钟的平均负载——粗略理解为”平均有多少个任务在使用或等待 CPU(Linux 还包括 D 状态等 IO 的进程)”。

关键在于:这个数字必须和 CPU 核数一起看。load 4.0 对单核机器是严重过载,对 16 核机器只是热身:

1
2
3
4
5
6
7
8
nproc
# 查看 CPU 核数,load average 除以这个数才是"每核负载"
# 经验法则:每核负载持续接近或超过 1,机器就开始排队了

uptime
# load average: 12.50, 8.20, 3.10
# 三个数字还能看趋势:1 分钟 > 15 分钟说明负载正在上升(事情正在恶化),
# 反过来说明高峰已经过去,正在恢复

开头那个问题的答案也在这:load 12.5 但 CPU 只用了 30%,多半是大量进程卡在 D 状态等 IO——load 算上了它们,CPU 却是闲的。这种”高 load 低 CPU”的组合,指向的是磁盘/网络存储瓶颈,不是 CPU 不够。

top:界面输出怎么读

top 进入后是实时刷新界面,上半部分是系统摘要,下半部分是进程列表:

1
2
3
4
5
6
7
8
9
top - 16:35:52 up 579 days, 22:14,  3 users,  load average: 1.12, 1.23, 1.27
Tasks: 230 total, 1 running, 229 sleeping, 0 stopped, 0 zombie
%Cpu(s): 14.3 us, 12.2 sy, 0.0 ni, 71.0 id, 0.0 wa, 0.0 hi, 0.0 si, 2.4 st
KiB Mem : 8008584 total, 680256 free, 5050156 used, 2278172 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2205612 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1747 root 20 0 4044748 166192 612 S 102.0 2.1 98860:42 dockerd
908 root 0 -20 11.3g 40368 4080 S 0.7 0.5 4186:36 etcd

摘要区第三行 %Cpu(s) 是整机 CPU 时间的分布,几个字段的含义:

1
2
3
4
5
6
7
us    用户态进程占的 CPU 时间(业务代码本身在跑)
sy 内核态占的时间(系统调用、内核在干活)——sy 明显偏高说明系统调用太频繁
ni 被调过 nice 值的进程占的时间
id 空闲——越高越闲
wa 等磁盘 IO 的时间——wa 高就是 IO 瓶颈的直接信号,和前面 D 状态的判断互相印证
hi/si 硬件/软件中断占的时间,平时接近 0
st 被宿主机偷走的时间——虚拟机/云服务器特有,st 持续偏高说明宿主机超卖了

进程列表里的前几列:

1
2
3
4
5
6
PR      内核眼中的调度优先级
NI nice 值,就是 nice/renice 设置的那个数——etcd 那行的 -20 是最高优先级
VIRT 虚拟内存,等同 ps 里的 VSZ,看看就好
RES 实际物理内存,等同 ps 里的 RSS,看内存占用盯这列
SHR 和其他进程共享的内存(共享库等),RES 里有一部分是它
S 进程状态,就是前面 ps 讲的 STAT 主状态那个字母

VIRT/RES/SHR 三列默认单位也是 KiB,和 ps 一致;数字大到一定程度 top 会自动换算并带上单位后缀——etcd 那行 VIRT 显示的 11.3g 就是换算成 GiB 后的结果。摘要区的内存两行更直接,行首就标了单位(KiB MemKiB Swap)。

上面这份输出里有个典型困惑:摘要行 CPU 加起来才用了不到 30%(us 14.3 + sy 12.2),下面 dockerd 一个进程却显示 102.0%——两边根本对不上?因为两处的分母不一样:摘要行是把所有核的时间摊平后按整机 100% 计算的;进程列表的 %CPU 是按单核 100% 计算的,多线程进程跑满多个核就会超过 100%(102% 就是占满了一个核再多一点)。所以 8 核机器上某进程 %CPU 400%,对应到摘要行也只贡献 50%。

看的时候配几个交互键:

1
2
3
4
5
P    按 CPU 占用排序(默认)
M 按内存占用排序
1 展开显示每个 CPU 核的占用——看负载是不是集中在单核上(单线程瓶颈的典型特征)
k 输入 PID 发信号杀进程
q 退出

free 怎么读:available 才是真正可用的

1
2
3
               total        used        free      shared  buff/cache   available
Mem: 15Gi 8.2Gi 1.1Gi 512Mi 6.2Gi 6.7Gi
Swap: 2.0Gi 0Gi 2.0Gi

最容易误读的就是 free 列:它只是”完全没被碰过的内存”。Linux 会把空闲内存尽量拿去做磁盘缓存(buff/cache),提高文件读写速度——这部分在应用需要时随时可以回收。所以:

  • 看 available,不看 free:available = 真正可分配给新程序的内存(含可回收的缓存),free 很小、available 充足是健康状态
  • Swap used 持续上涨才是真缺内存:物理内存实在不够,系统开始把内存页挪到磁盘上,性能会明显劣化——这才是需要处理的信号

组合实战:机器变慢了怎么定位

1
2
3
4
5
6
7
8
9
10
11
12
13
uptime
# 第 1 步:看 load average 和核数的比值,确认是不是真的过载,趋势是升是降

top
# 第 2 步:过载的话按 P 看谁吃 CPU;CPU 不高就怀疑 IO——
# 看进程列表里有没有一片 D 状态

free -h
# 第 3 步:看 available 是否枯竭、Swap 是否被大量使用
# 内存不足会连锁引发 CPU 和 IO 症状(频繁回收、swap 读写)

ps aux | awk '$8 ~ /^D/ {print}'
# 第 4 步:列出所有 D 状态的进程(第 8 列是 STAT),确认卡 IO 的是谁

命令参数速查表

前面重点在”输出怎么读”,命令本身的常用参数也汇总一份。

ps 常用参数

参数 作用
a 显示所有用户的进程,不只自己的
u 用户友好格式,带 %CPU/%MEM/VSZ/RSS/STAT 这些列
x 包含没有控制终端的进程(守护进程)
aux 以上三个连用,看全系统进程的标准姿势
-ef System V 风格的全进程列表,带 PPID(父进程)列
--sort=-%cpu 按 CPU 占用降序,-%mem 则按内存
-p PID 只看指定 PID 的进程

free 常用参数

参数 作用
-h 人类可读单位(K/M/G 自动换算)
-m / -g 固定按 MiB / GiB 显示
-s N 每 N 秒刷新一次,持续输出
-t 末尾多一行 Mem+Swap 的合计

top 启动参数(不多,常用就这几个):

参数 作用
-p PID 只监控指定进程
-d N 刷新间隔改为 N 秒,默认 3 秒
-b -n N 批处理模式输出 N 次后退出,适合重定向到文件留记录

指标速查表

ps aux 的指标

指标 怎么读
STAT R / S 运行中 / 正常睡眠等事件
STAT D 卡在 IO,不响应信号(kill -9 也没用),成片出现 = 磁盘/存储瓶颈
STAT Z 僵尸,处理它的父进程才有用
STAT T 被暂停(Ctrl-Z 或 SIGSTOP)
后缀 s / l / + 会话首进程 / 多线程 / 前台进程组
后缀 < / N 高优先级(nice 为负)/ 低优先级(nice 为正)
后缀 L 内存页锁定不允许换出,数据库进程常见
VSZ 虚拟地址空间,单位 KiB,大不代表问题
RSS 实际物理内存,单位 KiB,查内存泄漏盯它

top 的指标

指标/操作 怎么读
load average 除以 nproc 核数看每核负载,1/5/15 分钟对比看趋势
高 load + 低 CPU 典型 IO 瓶颈信号,去找 D 状态进程
%Cpu(s) 的 us / sy 用户态 / 内核态时间,sy 偏高 = 系统调用太频繁
%Cpu(s) 的 ni / id 调过 nice 的进程占比 / 空闲占比
%Cpu(s) 的 wa 等 IO 的时间占比,偏高 = IO 瓶颈,与 D 状态互相印证
%Cpu(s) 的 hi / si 硬件 / 软件中断,平时接近 0
%Cpu(s) 的 st 被宿主机偷走的时间,云服务器上持续偏高说明宿主机超卖
PR / NI 内核调度优先级 / nice 值
VIRT / RES / SHR 对应 ps 的 VSZ / RSS / 共享内存,默认 KiB,过大自动带 g 后缀
S 进程状态,同 ps 的 STAT 主状态
摘要行 %Cpu(s) 与进程 %CPU 对不上 分母不同:摘要按整机 100%,进程列按单核 100%
%CPU > 100% 多线程占多核的正常现象
P / M 按 CPU / 按内存排序
1 展开每核占用,识别单线程瓶颈
k / q 杀进程 / 退出

free 的指标

指标 怎么读
free 列 完全没被碰过的内存,很小不代表内存不够
buff/cache 系统拿去做磁盘缓存的内存,应用需要时可回收
available 真正可分配的内存(含可回收缓存),看这列下结论
Swap used 上涨 物理内存真不够的信号,性能开始劣化

写到这里

这三个命令的输出各有一个最值得记的点:ps 看 STAT(尤其警惕成片的 D)、load average 要除以核数再下结论、free 看 available 不看 free。把这几个指标读对,”机器慢”就能拆成 CPU、IO、内存三条线分头去查,而不是盯着满屏数字发懵。