type: note
title: Linux:五类资源告急排查(磁盘 / inode / CPU / 内存 / 僵尸)
date: 2026-11-05
description: 从一条现象走到「是哪一类资源 + 第一步看哪条命令」:df -h 与 df -i 分辨空间满和 inode 满;ps --sort=-pcpu 找吃满一个核的进程;journalctl -k 找 OOM killer 的尸检记录;ps 状态列 Z 认僵尸进程
tags: Linux, 排查, 磁盘, inode, 进程, 试点
Linux:五类资源告急排查
> 📌 GitHub:https://github.com/AR-firefly
笔记区
核心观点
**1. 五类资源告急的总判据表**
| 类型 | 现象 | 第一条命令 | 判据 |
| ---------- | ------------------------- | ---------------------------------- | ----------------------------------- |
| 磁盘空间满 | `No space left on device` | `df -h` | `Use%` 到 100% |
| inode 满 | **同一句报错** | `df -i` | `IUse%` 到 100%,而 `Use%` 只有 1% |
| CPU 打满 | 机器卡 | `ps -eo pid,pcpu,cmd --sort=-pcpu` | 单进程 `%CPU` ≈ 100 |
| 内存吃光 | 进程一声不吭消失 | `journalctl -k` | 有 `oom-kill:` / `Killed process` |
| 僵尸进程 | 进程表里多一行不干活的 | `ps -ef` | `STAT` 是 `Z`,`CMD` 带 `<defunct>` |
**2. 磁盘满和 inode 满是两个独立的池子**
两个盘报同一句 `No space left on device`,但坏的地方不一样:
| | 磁盘空间满 | inode 满 |
| --------------- | ---------------- | ----------------- |
| `df -h`(空间) | `64M 64M 0 100%` | `28M 152K 26M 1%` |
| `df -i`(号码) | 只有 1% | `32 32 0 100%` |
-
空间 = 存文件**内容**的地方(数据块)
-
inode = 每个文件的**身份记录**(权限、大小、内容放在哪几个块)
-
**空文件不占数据块,但一定占一个 inode**:所以建一堆空文件就能把号码耗光,空间一点没动
所以看到 `No space left on device`,**两条命令都要跑**:`df -h` 看是不是空间、`df -i` 看是不是号码。
**3. `df` 的两个参数作用不一样**
| 参数 | 改什么 | 结果 |
| ---- | ----------------------------------- | ----------------------------------- |
| `-h` | 只改**显示单位**(字节换成 K/M/G) | 还是空间那张表 |
| `-i` | **换一份数据**(空间表 → inode 表) | 表头变成 `Inodes IUsed IFree IUse%` |
两个一起写成 `df -hi`,出来的是**inode 那张表**------`-h` 只负责把数字变得好读,它没有权力决定看哪份数据。
**4. `dd` 的工作模型:搬运工**
从 `if=` 读一块 → 往 `of=` 写一块 → 重复。
| 部分 | 意思 |
| -------------- | ------------------------------------------------------------------------- |
| `if=/dev/zero` | 输入源。`/dev/zero` 是**设备文件**,读多少给多少值为 0 的字节,永远读不完 |
| `of=文件路径` | 输出目标,文件不存在就创建 |
| `bs=1M` | 一次搬多少(block size),默认 512 字节 |
| `count=N` | 搬几车就停;**不写就一直搬** |
停下的条件只有两个:**输入读完**、或者**写失败**。`/dev/zero` 永远读得完,所以只能等磁盘写满被拦下。
**写进去的是"很多个 0",不是"什么都没写"**------文件大小看写了多少字节,内容是什么无所谓。这就是用它造测试文件的原因。
**5. 查 CPU 要看单进程,不是整机**
20 核的机器,一个进程吃满一个核 = 整机只用了 1/20 ≈ **5%**。
看整机的 `%Cpu(s)` 会觉得"没事",实际上有一个核已经被榨干。所以第一步是**按进程排**:
-
`%CPU` = 单个进程吃一个核的百分比,**100 = 吃满一个核**
-
20 核全满才叫 2000
**6. OOM killer:内存不够时内核开枪**
-
OOM = **O**ut **O**f **M**emory
-
内存不够时,内核挑一个进程杀掉腾地方------牺牲一个,保整台机器
-
挑谁:按"坏分数"(badness)排,0 = 永不杀,1000 = 优先杀;每个进程的分数在 `/proc/<PID>/oom_score`
-
痕迹:`journalctl -k` 里 `oom-kill:` + `Killed process <PID> (<名字>)`
日志一行怎么读:
| 片段 | 意思 |
| -------------------------------------- | ----------------------------------- |
| `oom-kill:constraint=CONSTRAINT_MEMCG` | 触发了杀进程,原因是内存组超限 |
| `Memory cgroup out of memory` | 这个内存组没内存了 |
| `Killed process 9521 (python3)` | 被杀的是 PID 9521 的 python3 |
| `anon-rss:257440kB` | 实际占了约 251M,顶到了 256M 的上限 |
**7. 磁盘满 vs 内存满:两种死法**
| | 磁盘满 | 内存满 |
| ------------------ | ------------------------------------ | ------------------ |
| 谁报错 | **程序自己**拿到报错 | **内核直接开枪** |
| 程序有没有机会说话 | 有,会打印 `No space left on device` | 没有,一声不吭消失 |
| 去哪查 | 程序日志 / 终端 | `journalctl -k` |
所以「进程突然没了、日志里干干净净」要先怀疑 OOM。
**8. 僵尸进程:死了没人收尸**
-
子进程已经退出,**父进程没去回收**,内核只好保留它的登记信息
-
进程表里:`STAT` 是 `Z`,`CMD` 是 `名字 <defunct>`
-
它不占 CPU、不占内存,`TIME` 是 0,**只占着 PID 号**
-
` ` 方括号的含义:进程参数拿不到时,ps 用方括号把可执行文件名括起来
-
父进程退出后,init 会把它收走
**9. OOM 和僵尸:两种结局**
| | OOM 被杀 | 僵尸 |
| -------------- | ---------------- | ------------ |
| 进程表里还有吗 | **没有了** | **还有一行** |
| 占资源吗 | 不占(已经死了) | 只占 PID |
关键方法/流程
**磁盘空间满排查**
| 步 | 命令 | 判据 |
| --- | ----------------- | ----------------------------- |
| 1 | `df -h` | 找出哪个挂载点 `Use%` 到 100% |
| 2 | `du -sh <目录>/*` | 找出是哪个文件/目录占的 |
| 3 | 处理 | 删/挪/扩容 |
**inode 满排查**
| 步 | 命令 | 判据 |
| --- | ------------ | -------------------------- |
| 1 | `df -i` | 哪个挂载点 `IUse%` 到 100% |
| 2 | `df -h` 对照 | `Use%` 很低 → 不是空间问题 |
| 3 | 处理 | 删小文件多的目录 |
**CPU 打满排查**
| 步 | 命令 | 判据 |
| --- | ---------------------------------- | ---------------------------- |
| 1 | `ps -eo pid,pcpu,cmd --sort=-pcpu` | 第一行就是元凶,`%CPU` ≈ 100 |
| 2 | 处理 | `kill <PID>` |
**内存吃光排查**
| 步 | 命令 | 判据 |
| --- | -------------------- | -------------------------------- |
| 1 | 进程突然消失、无报错 | 先怀疑 OOM |
| 2 | `journalctl -k` | 找 `oom-kill` / `Killed process` |
| 3 | 处理 | 找出是哪个进程耗内存、限制它 |
**僵尸进程排查**
| 步 | 命令 | 判据 |
| --- | --------- | ---------------------------------------- |
| 1 | `ps -ef` | `CMD` 列找 `<defunct>`,`STAT` 是 `Z` |
| 2 | 看 `PPID` | 找它的父进程 |
| 3 | 处理 | 父进程不管,只能等父进程退出或杀掉父进程 |
实战记录
**记录 1:灌满 64M 小盘**
```
$ df -h ~/lab/d2/mnt_full
Filesystem Size Used Avail Use% Mounted on
tmpfs 64M 0 64M 0% /home/ar-26710/lab/d2/mnt_full
$ dd if=/dev/zero of=~/lab/d2/mnt_full/big bs=1M
dd: IO error: No space left on device
$ df -h ~/lab/d2/mnt_full
Filesystem Size Used Avail Use% Mounted on
tmpfs 64M 64M 0 100% /home/ar-26710/lab/d2/mnt_full
$ du -sh ~/lab/d2/mnt_full/*
64M /home/ar-26710/lab/d2/mnt_full/big
```
**记录 2:耗光 inode**
```
$ touch ~/lab/d2/mnt_inode/{1..30}
touch: cannot touch '/home/ar-26710/lab/d2/mnt_inode/21': No space left on device
...(21 到 30 全部失败)
$ df -i ~/lab/d2/mnt_inode
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/loop0 32 32 0 100% /home/ar-26710/lab/d2/mnt_inode
$ df -h ~/lab/d2/mnt_inode
Filesystem Size Used Avail Use% Mounted on
/dev/loop0 28M 152K 26M 1% /home/ar-26710/lab/d2/mnt_inode
```
空间还剩 26M,文件却建不出来------号码用完了。
**记录 3:CPU 满**
```
$ yes > /dev/null &
1 8050
$ ps -eo pid,pcpu,cmd --sort=-pcpu
PID %CPU CMD
8050 99.9 yes
85 0.0 /usr/lib/systemd/systemd-udevd
...
```
**记录 4:OOM 现场**
查到的内核日志:
```
kernel: oom-kill:constraint=CONSTRAINT_MEMCG,...
kernel: Memory cgroup out of memory: Killed process 9521 (python3) total-vm:2370148kB, anon-rss:257440kB ...
```
**记录 5:僵尸进程**
```
$ ps -ef
ar-26710 8198 8196 0 23:06 ? 00:00:00 python3 <defunct>
```
线索区(学完后合上材料,自问自答)
**Q: 五类资源告急,各自第一条命令是什么?**
A: 磁盘 `df -h`;inode `df -i`;CPU `ps -eo pid,pcpu,cmd --sort=-pcpu`;内存 `journalctl -k`;僵尸 `ps -ef` 看 `STAT`。
**Q: 同样一句 `No space left on device`,怎么分清是空间满还是 inode 满?**
A: 两条都跑。`df -h` 到 100% = 空间满;`df -h` 很低但 `df -i` 到 100% = inode 满。
**Q: 为什么不写 count 的 dd 会一直跑?**
A: 它停的条件是输入读完或写失败。`/dev/zero` 永远读不完,所以只能等磁盘写满。
**Q: 写进文件的都是 0,为什么还占空间?**
A: 文件大小看写了多少**字节**,不看内容是什么。64M 个 0 照样占 64M。
**Q: 20 核机器上一个进程 100%,整机显示多少?**
A: 约 5%。所以看整机看不出来,必须按进程排。
**Q: 进程突然消失、日志里没报错,先怀疑什么?**
A: OOM killer。去 `journalctl -k` 找 `oom-kill` / `Killed process`。
**Q: `df -hi` 出来的是哪张表?**
A: inode 那张。`-i` 决定看哪份数据,`-h` 只决定数字好不好读。
**Q: 僵尸进程占什么资源?**
A: 只占 PID 号,不占 CPU 也不占内存,`TIME` 是 0。
**Q: `(sd-pam)` 和 `python3 <defunct>` 有什么区别?**
A: 圆括号是正常进程(参数拿不到时的显示方式),方括号加 `<defunct>` 才是僵尸。
总结(50字以内,用自己的话概括今天学到了什么)
磁盘满看 df -h,号码满看 df -i;CPU 看单进程;内存被 OOM 杀查 journalctl -k;僵尸看 Z。
复习卡片
| 概念 | 必学/了解 | 一句话 | 场景 |
| ----------------- | --------- | ---------------------------------------- | -------------------- |
| `df -h` | 必学 | 看文件系统空间用量,`-h` 换成 M/G | 磁盘满第一步 |
| `df -i` | 必学 | 看 inode 用量,`-i` 换一份数据 | 空间没满却建不了文件 |
| inode | 必学 | 文件的户口号,每个文件扣一个,空文件也扣 | 判断号码有没有用完 |
| `du -sh` | 了解 | 只看某个目录/文件占多大;`man 1 du` | 找出是谁占的 |
| `%CPU` | 必学 | 单进程吃一个核的百分比,100 = 满一个核 | 找 CPU 元凶 |
| OOM killer | 必学 | 内存不够时内核按分数挑进程杀 | 进程无声消失 |
| `journalctl -k` | 必学 | 只看内核日志,`-k` = kernel | 查 OOM / 内核事件 |
| `<defunct>` / `Z` | 必学 | 子进程已死、父进程没收尸 | 僵尸进程 |
| `df -hi` | 了解 | 出来的是 inode 表,`-h` 不改看哪份数据 | 参数组合 |
| `load average` | 了解 | 系统负载均值;`man 1 uptime` | 看整体压力 |
流程附加段
旧知识回收
| 概念 | 一句话 | 出处 |
| -------------------------- | -------------------------------------------------------------------------------------- | ---------- |
| 端口开 ≠ 服务能用 | `LISTEN` 只说明内核在等连接;要 `curl` 敲门拿到回应才算能用 | 复习 11-02 |
| `ping` vs `curl` | `ping` 走 ICMP,敲的是**机器**,不认识端口;`curl` 走 TCP/HTTP,敲的是**端口上的服务** | 复习 11-02 |
| 三层判断 | 门开没开(`LISTEN`)→ 人进没进来(三次握手)→ 进来有没有人理(应用层回应) | 复习 11-02 |
| `journald` vs `journalctl` | `d` 结尾是后台服务,`ctl` 结尾是手里的命令 | 点 4 |
| `-u` vs `-k` | `-u` 按服务(unit)筛,`-k` 只看内核 | 点 4 |
| `-bash` 的横杠 | 表示登录 shell,不是报错 | 点 5 |
| `(sd-pam)` 圆括号 | 正常进程参数拿不到时的显示方式,不是僵尸 | 点 5 |
今日产出验收
| 产出条 | 证据 | 结果 |
| ------------------------ | ------------------------------------------------------------------------ | ---- |
| 五类各造一次现象 | 记录 1--5 全部有真实输出 | 过 |
| 五类各用一条命令定位 | 复盘第 1 问答出 `df -h` / `df -i` / `ps --sort` / `journalctl -k` / `ps` | 过 |
| 磁盘满 vs inode 满能分清 | 两个盘对照,`Use%` 与 `IUse%` 一个 100 一个 1 | 过 |
| 进程突然消失知道去哪查 | 复盘第 3 问答出 `journalctl -k` 找 `oom-kill` | 过 |