LabHub

博客

htop 与 top 完全解剖 — 读懂每一个数字

한국어English日本語中文

引言 — 数字的洪流

第一次在 Linux 服务器上打开 htoptop,会被数字和颜色的洪流淹没。大多数人只是粗略瞥一眼 CPU 和内存的百分比,其余的全部忽略,但那每一个数字里,其实都藏着诊断系统状态所需的信息。最近,佩特里斯·尼基福罗夫斯(Pēteris Ņikiforovs)的名解说《Explanation of everything you can see in htop》再度登上 Hacker News 榜单前列,重新点燃了这个话题 — 借这个契机,本文把这些字段逐一拆开来看。

读懂进程列

先来看看进程列表里每一列各自代表什么。

VIRT、RES、SHR — 三个内存值的陷阱

内存列是最常被误解的部分,这三个值的含义完全不同。

由此得出一条重要的实务经验:寻找内存吃紧的进程时,应该按 RES 而不是 VIRT 排序。按 VIRT 排序的话,那些实际上没怎么用内存、只是地址空间占得大的进程会被排到最前面,容易造成误判。

进程状态字母

S 列显示一个单字母的进程状态,各字母含义如下。

负载均值 — 它不是 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 上方的条形仪表也用颜色传递信息。

这里要注意,不要把 buffers 和 cache 误当成"被占用的内存"。缓冲区和缓存是内核为了性能临时借用的区域,一旦应用程序需要内存,会立刻归还。所以真正该关注的值不是"used",而是 可用内存(available)。这也是为什么 Linux 上"内存几乎占满"的画面通常并不是问题 — 被缓存占用的内存,实质上是随时可以腾出来的富余内存。

僵尸进程的真面目

僵尸(Z)进程经常被误解,这里整理几个事实。

僵尸是已经死掉的进程。它已经执行结束,只是父进程还没有回收(reap)它的退出状态,所以进程表里只剩下一条条目。因此僵尸 完全不消耗内存,只占据进程表里的一个槽位。

另外,僵尸 无法被杀死。要终止一个进程需要发送信号,而信号只有活着的进程才能接收。向一个已经死了的僵尸发送 kill -9 毫无意义。僵尸消失的唯一途径,是父进程把它回收掉。如果父进程先于它死亡,僵尸会被 init(PID 1)收养,由 init 代为回收。

也就是说,看到几个僵尸不必惊慌。如果僵尸持续堆积,与其说是僵尸本身的问题,不如说是它指向了一个信号——某个父进程存在没有正确回收子进程的 bug。

写时复制与 RES 的错觉

再补充一个微妙的现象。当一个进程用 fork 创建子进程时,Linux 会使用 写时复制(copy-on-write)。父子进程共享同一批物理内存页,只有在其中一方发生写入时,才会复制那一页。

正因如此,htop 中父进程和子进程可能各自完整显示全部 RES。表面上看像是用了两倍的内存,但实际的物理内存是共享的,总量并没有那么大。在查看频繁 fork 子进程的程序的内存占用时,要记住这个错觉。

实战诊断清单

把以上内容套用到实际问题排查中,大致如下。

如果想在浏览器里亲自动手试试这些工具,可以打开本站的Linux 终端Web 终端;想看看内核参数如何影响这些行为,可以一并打开内核参数浏览器

结语

htop 和 top 里的数字,乍看像密码,但一旦理解了每个字段的含义,它们就会变成读懂系统状态的强大诊断工具。尤其是 VIRT 与 RES 的区别、负载均值包含 I/O 等待这一事实、以及缓存实质上是富余内存这一点 — 只要把这三条真正弄懂,服务器问题排查就已经解决了一半。

参考资料

评论

还没有评论。

登录后即可发表评论