Linux 用五个字母描述进程:R 在跑或想跑、S 在等、D 在等硬件、T 被停住、Z 已死待收。关键不是背字母,是知道【状态就是它挂在哪个队列】。
4.5 讲换人要花钱,那什么时候该换?答案是【状态变了的时候】。这一节先把状态这几个名字立住。
一、五个字母,各是什么
R(Running/Runnable):正在 CPU 上跑,或者在就绪队列里排队。它想跑,也随时能跑。
S(Interruptible Sleep):在等一个事件(IO 完成、信号、定时器)。能被信号叫醒,所以叫可中断。
D(Uninterruptible Sleep):在等硬件,连 kill -9 都杀不掉,只能等它自己回来。
T(Stopped):被 SIGSTOP 或调试器停住。它没死,只是不动。
Z(Zombie):已经结束,但父进程还没读它的退出码。只剩一条记录。
二、状态不是标签,是队列
这句话是理解调度的关键:内核里没有【状态变量】这种浪漫的东西,它就是几个链表。 就绪队列:所有 R 状态、等着被挑的进程。调度器只从这个队列里挑人。 等待队列:每个可能发生的事件都有一条(等磁盘、等网络、等锁、等定时器)。事件发生时,内核把对应的进程从等待队列挪到就绪队列——这就叫【唤醒】。 所以【状态转换】本质是【换队列】。而【唤醒】只是给了排队资格,不是给了 CPU。
三、为什么 S 状态的进程最多
因为程序大部分时间都在等。等磁盘、等网络、等用户输入、等定时器。
一份 ps aux 里九成的进程是 S,这很正常,不是故障。
反过来,如果一台机器上 R 状态的进程特别多(比如是核数的好几倍),说明 CPU 真的不够用——大家在排队。
这个观察在排查时很好用:ps -eo stat | sort | uniq -c 一眼看出分布。
四、D 状态为什么可怕
因为它【不可中断】。S 状态你能用信号叫醒,D 状态连内核都不响应信号——它在等一个必须等完的硬件操作。 常见成因:磁盘坏道、NFS 服务器失联、某些驱动 bug。 后果:进程杀不死、卸载文件系统卸不掉、关机卡住。只能等硬件回来或者硬重启。 所以看到一堆 D,先查存储和网络文件系统,别急着调调度器。
五、动手 Demo:进程的状态——五个名字就够描述一切
这一节把五个状态码与【它挂在哪个队列】对上,再补一张【谁来动它】的表。 看清一件事:状态不是标签,是位置。
# Linux 的进程状态码(ps 的 STAT 列首字母)
STATES = {
"R": "运行中/就绪——正在跑,或排队等着跑",
"S": "可中断睡眠——在等事件,能被信号叫醒",
"D": "不可中断睡眠——在等硬件,kill -9 也杀不掉",
"T": "停止——被 SIGSTOP 或调试器停住",
"Z": "僵尸——已结束,等父进程读退出码",
}
for k, v in STATES.items():
print(k, v)
实跑输出:
--------------------------------------------------------------------
进程的状态——五个名字就够描述一切
--------------------------------------------------------------------
① Linux 上真实的状态码
状态 ps 里显示 含义
----------------------------------------------------------
运行中/就绪 R 正在跑,或排队等着跑
可中断睡眠 S 在等事件(IO 完成、信号)
不可中断睡眠 D 在等硬件,连 kill 都杀不掉
停止 T 被 SIGSTOP 或调试器停住
僵尸 Z 已结束,等父进程读退出码
**R 与 S 的区别最值得记**:R 是【想跑】,S 是【在等】。
**一台机器上绝大多数进程都是 S**——因为大部分时间它们都在等。
② 状态不是标签,是【它在哪个队列里】
状态 挂在哪 谁来动它
-----------------------------------------------------
R 就绪队列 / CPU 上 调度器
S 等待队列(某个事件) 事件发生的内核代码
Z 进程表里的一条记录 父进程 wait
**所以【状态转换】本质是【换队列】。**
**从等待队列挪到就绪队列,就叫【被唤醒】。**
R 与 S 的区别最值得记:R 是【想跑】,S 是【在等】。一台机器上绝大多数进程都是 S。
Z 与 T 的区别也很实用:Z 是已经死了、只是没被收尸;T 是活着但不动(可以被 SIGCONT 恢复)。
这五个字母你会在 ps、top、/proc/<pid>/status 里反复见到,而且它们是排查问题的第一手线索——比看 CPU 占用率更早暴露问题。
📋 在真 Linux 上数一遍:ps -eo stat | cut -c1 | sort | uniq -c | sort -rn,你会看到 S 占绝大多数,R 只有几个。
30 秒实验
ps -eo stat,pid,comm | head -20,逐个猜它们是 R 还是 S,再想想为什么。sleep 300 &然后ps -o stat,cmd -p $!——看后台的 sleep 是 S 还是 R。cat /proc/self/status | grep State——self指向正在读它的那个进程。
常见误区
- 【状态是内核给进程贴的标签】。它是【进程挂在哪个队列】的直接体现。调度器只从就绪队列里挑人。
- 【D 状态是卡死了】。它在等一个真实的硬件操作。杀掉它没用,得解决硬件或那个 IO。
- 【S 状态的进程是在偷懒】。它在等。等的时间也是用户等的时间,一点没省。
自测三问(点开对答案)
1. 五个状态码各是什么?哪个最常见? —— R 运行/就绪、S 可中断睡眠、D 不可中断睡眠、T 停止、Z 僵尸。**S 最常见**,因为程序大部分时间在等。 2. 为什么说【状态就是它挂在哪个队列】? —— 内核用几个链表管理进程:就绪队列装 R,等待队列装 S/D。**唤醒就是换队列**,而换队列不等于拿到 CPU。 3. D 状态为什么连 kill -9 都杀不掉? —— 它在等不可中断的硬件操作,**内核不在这里检查信号**。只能等操作完成或硬重启。- ☐ 4.7 状态转换
相关笔记
- 结束进程 — 僵尸的成因
- 状态转换 — 哪些转换合法
- 进程睡眠 — S 状态的实战
- 🐧 Linux是怎样工作的 · 索引