- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 引言 — 数字的洪流
- 读懂进程列
- VIRT、RES、SHR — 三个内存值的陷阱
- 进程状态字母
- 负载均值 — 它不是 CPU 使用率
- 仪表条的颜色
- 僵尸进程的真面目
- 写时复制与 RES 的错觉
- 实战诊断清单
- 结语
- 参考资料
引言 — 数字的洪流
第一次在 Linux 服务器上打开 htop 或 top,会被数字和颜色的洪流淹没。大多数人只是粗略瞥一眼 CPU 和内存的百分比,其余的全部忽略,但那每一个数字里,其实都藏着诊断系统状态所需的信息。最近,佩特里斯·尼基福罗夫斯(Pēteris Ņikiforovs)的名解说《Explanation of everything you can see in htop》再度登上 Hacker News 榜单前列,重新点燃了这个话题 — 借这个契机,本文把这些字段逐一拆开来看。
读懂进程列
先来看看进程列表里每一列各自代表什么。
- PID:进程 ID,进程启动时被分配的唯一编号。
- USER:进程的所有者,也就是启动该进程的用户。
- PRI 与 NI:优先级(priority)和 nice 值。二者的关系是
PR = 20 + NI。nice 值的范围是 -20(最高优先级)到 19(最低优先级),nice 值越低,分配到的 CPU 越多。粗略估算,nice 每变化一级,大约会转移 10% 的 CPU 时间。 - VIRT / RES / SHR:三个与内存相关的值,下面单独讲解。
- S:进程状态(state),同样在下面讲解。
- %CPU:CPU 使用率。
- %MEM:内存使用率,计算方式是
RES / 总 RAM。 - TIME+:进程迄今累计使用的 CPU 时间。
VIRT、RES、SHR — 三个内存值的陷阱
内存列是最常被误解的部分,这三个值的含义完全不同。
- VIRT(虚拟内存):进程已保留的整个虚拟地址空间。这里面包含实际并未使用的区域、共享库、内存映射文件,甚至已被换出到交换分区的页面。所以 VIRT 通常会被夸大,作为实际内存使用量的指标几乎没有参考价值。
- RES(常驻内存):未被换出、实际驻留在物理 RAM 中、进程正在真正使用的内存。想知道"这个进程现在到底吃了多少 RAM",看的就是这个值。
- SHR(共享内存):可能与其他进程共享的内存,典型例子就是共享库。
由此得出一条重要的实务经验:寻找内存吃紧的进程时,应该按 RES 而不是 VIRT 排序。按 VIRT 排序的话,那些实际上没怎么用内存、只是地址空间占得大的进程会被排到最前面,容易造成误判。
进程状态字母
S 列显示一个单字母的进程状态,各字母含义如下。
R— 正在运行或可运行(runnable)。正在 CPU 上执行,或者正在排队等待轮到自己。S— 可中断睡眠(interruptible sleep)。正在等待某个事件而休眠,但可以被信号唤醒。平时大多数进程都处于这个状态。D— 不可中断睡眠(uninterruptible sleep)。通常是在等待磁盘 I/O,连信号也无法唤醒它。Z— 僵尸(zombie)。已经终止,但父进程尚未回收(reap)它。T— 被任务控制信号停止的状态(例如 Ctrl+Z)。t— 被调试器/跟踪器停止的状态。
负载均值 — 它不是 CPU 使用率
被误解得最广泛的指标是 负载均值(load average)。人们常以为它等同于"CPU 使用率",但事实并非如此。
第一,负载均值不是简单平均,而是 指数衰减移动平均。屏幕上会显示 1 分钟、5 分钟、15 分钟三个值,越近的数值权重越大。1 分钟值大致是把最近 1 分钟的负载按 63%、之前的负载按 37% 左右混合而成。
第二,也是更重要的一点 —— 负载计入的不只是运行中(R)的进程,处于不可中断睡眠(D)状态的进程也会一并计入。正因如此,负载高并不必然代表 CPU 繁忙。等待磁盘或网络 I/O 的进程一多,负载照样会飙升。
第三,负载值必须结合核心数来解读。在拥有 N 个核心的机器上,负载值为 N 大致意味着已达到 100% 利用状态。核心数为 4 而负载为 4,就是饱和状态;核心数为 8 而负载为 4,则只用了一半。
把这三点综合起来,就能得出一条强有力的诊断规则:负载高但 %CPU 低,十有八九是 I/O 等待(I/O wait)。这时候,查找处于 D 状态的进程,就是排查问题的起点。
仪表条的颜色
htop 上方的条形仪表也用颜色传递信息。
- CPU 仪表:蓝色代表低优先级(nice 值为正)的线程,绿色代表普通优先级线程,红色代表内核线程。(htop 有时还会更细地拆分出虚拟化、I/O 等待等类别。)
- 内存仪表:绿色是实际被使用的内存(used),蓝色是缓冲区(buffers),橙色是缓存(cache)。
这里要注意,不要把 buffers 和 cache 误当成"被占用的内存"。缓冲区和缓存是内核为了性能临时借用的区域,一旦应用程序需要内存,会立刻归还。所以真正该关注的值不是"used",而是 可用内存(available)。这也是为什么 Linux 上"内存几乎占满"的画面通常并不是问题 — 被缓存占用的内存,实质上是随时可以腾出来的富余内存。
僵尸进程的真面目
僵尸(Z)进程经常被误解,这里整理几个事实。
僵尸是已经死掉的进程。它已经执行结束,只是父进程还没有回收(reap)它的退出状态,所以进程表里只剩下一条条目。因此僵尸 完全不消耗内存,只占据进程表里的一个槽位。
另外,僵尸 无法被杀死。要终止一个进程需要发送信号,而信号只有活着的进程才能接收。向一个已经死了的僵尸发送 kill -9 毫无意义。僵尸消失的唯一途径,是父进程把它回收掉。如果父进程先于它死亡,僵尸会被 init(PID 1)收养,由 init 代为回收。
也就是说,看到几个僵尸不必惊慌。如果僵尸持续堆积,与其说是僵尸本身的问题,不如说是它指向了一个信号——某个父进程存在没有正确回收子进程的 bug。
写时复制与 RES 的错觉
再补充一个微妙的现象。当一个进程用 fork 创建子进程时,Linux 会使用 写时复制(copy-on-write)。父子进程共享同一批物理内存页,只有在其中一方发生写入时,才会复制那一页。
正因如此,htop 中父进程和子进程可能各自完整显示全部 RES。表面上看像是用了两倍的内存,但实际的物理内存是共享的,总量并没有那么大。在查看频繁 fork 子进程的程序的内存占用时,要记住这个错觉。
实战诊断清单
把以上内容套用到实际问题排查中,大致如下。
- "负载高但 CPU 很闲" → I/O 等待。查找
D状态的进程,怀疑磁盘或网络瓶颈。 - 找出吃内存的元凶 → 按 RES 而不是 VIRT 排序。
- 找出失控的线程 → 在 htop 中打开线程显示,观察
%CPU持续偏高的条目。 - "内存满了" → 看 available 而不是 used。被缓存占用不是问题。
如果想在浏览器里亲自动手试试这些工具,可以打开本站的Linux 终端或Web 终端;想看看内核参数如何影响这些行为,可以一并打开内核参数浏览器。
结语
htop 和 top 里的数字,乍看像密码,但一旦理解了每个字段的含义,它们就会变成读懂系统状态的强大诊断工具。尤其是 VIRT 与 RES 的区别、负载均值包含 I/O 等待这一事实、以及缓存实质上是富余内存这一点 — 只要把这三条真正弄懂,服务器问题排查就已经解决了一半。