当前位置:首页>Linux>Linux 进程管理全景图:ps / top / kill / 信号 / 僵尸孤儿 / 容器时代

Linux 进程管理全景图:ps / top / kill / 信号 / 僵尸孤儿 / 容器时代

  • 2026-09-09 10:20:21
Linux 进程管理全景图:ps / top / kill / 信号 / 僵尸孤儿 / 容器时代
"服务又挂了"、"机器 CPU 100%"、"内存被吃光"、"进程杀不掉"……一个合格的 Linux 运维 / 后端工程师,必须对进程这件事的来龙去脉了如指掌。这篇把进程的基础概念 → 监控 → 排查 → 控制 → 现代化工具串成一篇,方便随时回查。

一、3 个基础概念,先分清

名词含义通俗类比
程序(Program)静态的安装包 / 可执行文件,躺在磁盘上菜谱
进程(Process)程序被加载到内存运行起来的实例,有 PID、有内存、有 CPU 时间片正在做的菜
守护进程(Daemon)一直运行在后台的进程,通常以 d 结尾,如 sshd / crond / nginx24h 营业的厨房

补一个 2026 年常被混淆的:

  • 线程(Thread):进程里的"小弟",共享同一份内存空间,调度单位是线程

  • 容器(Container):本质就是一组被 namespace / cgroups 隔离的进程,不是虚拟机


二、两种"异常"进程:僵尸 vs 孤儿

2.1 僵尸进程(Zombie)

子进程已经结束,但父进程没有调用 wait() 回收,于是子进程的 PCB 残留在内核里,状态变 Z。

特征:

  • 不占 CPU、不占内存(已 free)

  • 占着 PID(PID 总量有限,默认 32768)

  • 数量爆炸会导致 fork 失败

排查:

ps aux | awk '$8 ~ /Z/ {print}'top -bn1 | awk 'NR==2'# Tasks 行直接告诉你 zombie 数

解决:

  • 方案 1:找出僵尸的父进程,让父进程 wait() 或重启父进程

  • 方案 2:父进程已经是 systemd(PID 1),那就升级 / 重启服务,必要时重启机器

# 找父进程ps -o ppid= -p <僵尸PID>kill -HUP <父进程PID>          # 通知父进程"清账"

2.2 孤儿进程(Orphan)

父进程先死了,子进程还在跑。这种进程会被 systemd(PID 1)领养,不算异常。

孤儿不是问题,僵尸才是。

2.3 工具提示

# 树形看父子关系(来自 psmisc 包)yum install psmisc -y# Rocky/RHELpstree -ppstree -p <pid>

三、ps —— 静态快照

3.1 两种"方言"

风格例子备注
BSD 风格ps aux列多、最常用
System V 风格ps -ef列简洁、与 awk 配合好
GNU 长选项ps --sort=-%mem排序方便

3.2 ps -ef

UID    PID  PPID  C STIME TTY      TIME CMD
列含义
UID所属用户
PID进程号
PPID父进程号
CMD命令本身([] 括起来的是内核线程)

3.3 ps aux 各列含义

列号名字说明
1USER所属用户
2PID进程号
3%CPUCPU 使用率
4%MEM内存使用率
5VSZ虚拟内存大小(KB)
6RSS物理内存大小(KB)
7TTY控制终端(? 表示没有)
8STAT进程状态
9START启动时间
10TIME累计 CPU 时间
11+COMMAND命令本体

3.4 进程状态(STAT)

基础状态:

状态含义
RRunning,正在运行 / 就绪
SSleeping,可中断睡眠(大部分守护进程)
D不可中断睡眠(通常在做磁盘 IO,强杀不掉)
T停止 / 挂起(被 Ctrl+Z 或 SIGSTOP)
Z僵尸
X已死(极少见)

附加修饰符:

符号含义
ssession leader(领导者,如 Ss)
+前台进程组(如 R+)
l多线程(如 Sl)
<高优先级
N低优先级

💡 看到一堆 D 状态的进程还杀不掉?基本就是磁盘 hang 了(NFS 卡死、磁盘故障),看 dmesg 和 iostat。


四、top —— 动态监控

4.1 头部 5 行(一定要会读)

top - 10:23:45 up 12 days,  4:21,  3 users,  load average: 0.42, 0.55, 0.61Tasks: 198 total,   1 running, 197 sleeping,   0 stopped,   0 zombie%Cpu(s):  3.5 us,  1.2 sy,  0.0 ni, 95.1 id,  0.1 wa,  0.0 hi,  0.1 si,  0.0 stMiB Mem :  7820.5 total,  1290.3 free,  3950.4 used,  2579.8 buff/cacheMiB Swap:  2048.0 total,  2048.0 free,     0.0 used.  3650.1 avail Mem

重点指标:

  • load average1/5/15 分钟平均负载,理想值 ≤ CPU 核数

  • %Cpu 中的 wa:IO 等待,长期 > 10% 多半是磁盘瓶颈

  • %Cpu 中的 st:被 hypervisor 偷走的时间(云主机被超卖)

  • buff/cache:不是真正占用,可释放

  • avail Mem:真正可用内存,比 free 更准确

  • Tasks ... zombie:直接告诉你僵尸数

4.2 交互快捷键

键作用
q退出
空格立即刷新
P按 CPU 排序(默认)
M按 MEM 排序
T按累计 CPU 时间排序
c显示完整命令行
1展开每个 CPU 核
z / b彩色 / 高亮
x标出当前排序列
Shift+< / >切换排序列
k直接 kill 指定 PID
rrenice 改优先级
f选择要显示的列
W保存配置到 ~/.toprc

4.3 非交互模式(脚本必备)

top -bn1 | head -20top -bn1 | awk 'NR==2 {print $(NF-1), $NF}'# 输出僵尸数top -bn1 -p <PID>                              # 只看某个 PID

4.4 进阶替代品(强烈推荐)

工具亮点
htop彩色、支持鼠标、可视化树形(EPEL 源)
btop颜值天花板,CPU / 内存 / 网络 / 进程一屏看
glances全系统监控,支持远程 API、Web UI
nmonIBM 系老牌监控,能录历史
bpytop / bottomRust / Python 风味的现代 top
dnf install -y htop btop glances

五、原文没讲,但必须会:杀进程 + 信号

5.1 三把"杀刀"

kill-SIGNAL PID            # 按 PIDpkill   -SIGNAL  pattern        # 按名字 / 用户 / 终端kill all -SIGNAL  name           # 按精确名字pgrep   -l       pattern        # 只查不杀

5.2 常用信号

信号编号含义
SIGHUP1挂起 / 重新读配置(如 kill -HUP nginx)
SIGINT2Ctrl+C,温柔中断
SIGQUIT3Ctrl+\,带 core dump 退出
SIGKILL9强杀,不可被捕获,最后手段
SIGTERM15默认,请进程优雅退出
SIGSTOP / SIGCONT19 / 18挂起 / 恢复
SIGUSR1 / SIGUSR210 / 12用户自定义(nginx reopen 日志用 USR1)

5.3 实战

kill 12345# 默认 SIGTERM,优雅kill -9 12345# 不响应?再上 SIGKILLpkill -9 -f 'python.*worker'# 按完整命令行匹配pkill -u user001                  # 杀掉某个用户所有进程kill all -HUP rsyslogd             # 让 rsyslog 重新加载配置

⚠️ kill -9 是最后手段,会让进程没机会做清理(关 fd、刷脏页),可能导致数据丢失、临时文件泄漏。


六、原文没讲:前后台 / 优先级 / 守护化

6.1 前后台与作业控制

sleep 1000 &              # 直接放后台jobs                      # 看当前 shell 的作业fg %1                     # 把作业 1 调回前台bg %1                     # 让被 Ctrl+Z 暂停的作业继续在后台跑Ctrl+Z                    # 暂停前台作业(变 T 状态)

6.2 退出终端不被杀

nohup ./long_job.sh > job.log 2>&1 &disown -h %1              # 给已在后台的作业"摘绑"setsid ./long_job.sh      # 直接新建会话

推荐用 tmux / screen 直接挂着,比 nohup 优雅。

6.3 调优先级:nice / renice

nice -n 10 ./batch.sh          # 启动时降优先级(值越大越"礼让")renice -n -5 -p 12345# 调高已有进程的优先级(root 才行)chrt -f 50 ./realtime.bin      # 实时调度(FIFO 50 优先级)ionice -c 2 -n7 ./scan.sh       # 调 IO 优先级

七、原文没讲:/proc/<pid> 与现代调试工具

7.1 /proc/<pid> 信息金矿

ls /proc/$(pgrep -n nginx)/# cmdline   完整命令行# environ   环境变量# status    可读状态(含线程数、内存细节)# fd/       打开的文件描述符# maps      内存映射# limits    进程级 ulimit# cgroup    所属 cgroup
cat /proc/<pid>/status   | grep -E 'Vm|Threads|State'ls  /proc/<pid>/fd       | wc -l# 打开了多少 fd

7.2 必备排障工具

工具用途
pidstat 1按进程出 CPU / IO / 内存采样
pmap <pid>看进程内存映射
lsof -p <pid>看进程打开了哪些文件 / socket
strace -p <pid>跟踪系统调用(线上谨慎,会让进程变慢)
ltrace -p <pid>跟踪库函数调用
perf top -p <pid>性能采样
bpftrace / bcc-toolseBPF 现代追踪

八、原文没讲:systemd 才是 PID 1

现代 RHEL 8/9/10、Ubuntu 22.04/24.04 都是 systemd,别再 kill -9 服务,应该:

systemctl start  nginxsystemctl reload nginx               # 等价 kill -HUPsystemctl restart nginxsystemctl status  nginx              # 看状态、最近日志、主进程 PIDsystemd-cgls                          # 树形看所有服务的 cgroupsystemd-cgtop                         # 类 top,按 cgroup 看 CPU/内存journalctl -u nginx -f# 跟踪服务日志

8.1 限制资源(替代手写 cgroup)

# 临时给某服务限内存systemctl set-property nginx.service MemoryMax=512Msystemctl set-property nginx.service CPUQuota=50%

8.2 一行命令开个临时受限"沙箱"

systemd -run --scope -p MemoryMax=200M -p CPUQuota=20% ./script.sh

九、案例集合(生产高频)

9.1 过滤指定进程

ps -ef | grep crond | grep -v grepps -ef | grep crond | grep -v grep | wc -lpgrep -a crond                       # 更现代的写法

9.2 树形看父子关系

pstree -ppstree -p $(pgrep -n sshd)ps auxf

9.3 只取需要的列

ps aux | awk '{print $1,$3}'ps axo user,%cpu,stat,cmdps --no-heading axo user,%cpu,stat

9.4 单独抓某个服务

ps --no-heading -o pid,%cpu,%mem,command -C crond

9.5 内存 / CPU Top 5

ps aux --sort=-%mem | head -6# 含表头ps aux --sort=-%cpu | head -6ps --no-headers aux | sort -rnk4 | head -5

9.6 用 awk 玩"最后一列"

echo 1 a b user001 996 | awk '{print $NF}'# 996echo 1 a b user001 996 | awk '{print $(NF-1)}'# user001echo 1 a b user001 996 | awk '{print $NF-1}'# 995(算术)

9.7 一行拿到僵尸数

top -bn1 | awk 'NR==2 {print $(NF-1), $NF}' # 输出例:0 zombie

十、容器 / K8s 时代的"进程观"

容器不是虚拟机,进程仍然跑在宿主机的内核上:

# 宿主机看,所有容器进程都是宿主机的进程ps -ef | grep -v grep | grep containerd-shim# 进容器 namespace 看,会觉得自己是 PID 1nsenter -t <宿主机PID> -a ps -ef# K8s 排障kubectl top pod -Akubectl exec -it <pod> --topcrictl pscrictl stats

容器里的"僵尸"特别常见,原因:

  • 容器主进程通常不是 init,没人回收子进程

  • 解决:用 tini / dumb-init 当 PID 1,或者镜像里 --init

docker run --init my-app

十一、避坑清单

  1. ✅ kill 先发 15(SIGTERM),再不行才上 9(SIGKILL)

  2. ✅ D 状态进程杀不掉是正常的,查磁盘 / NFS / 卷

  3. ✅ 用 pgrep -f / pkill -f 时模式要精准,否则误杀自己当前 shell

  4. ⚠️ grep 自己也会被 ps | grep xxx 抓到,记得加 grep -v grep

  5. ⚠️ nohup 启动的进程退出终端后日志默认追加到 nohup.out,磁盘会被悄悄写满

  6. ⚠️ 容器里跑长任务记得加 --init,否则子进程会变僵尸

  7. ⚠️ top / ps 看到的 %MEM 不是真实独占,多进程共享内存会被重复计算(推荐 smem)

  8. ⚠️ swap 用得多不代表内存不够,关键看 si/so(实时换入换出)


十二、一句话总结

看快照用 ps,盯实时用 top/htop/btop,杀进程先 15 后 9,父子关系看 pstree,深度排障靠 /proc + pidstat + strace + bpftrace,服务管理走 systemd,资源限制走 cgroups,容器时代别忘 --init。

如果觉得有用,欢迎点赞 / 在看 / 转发给身边正在和"OOM / CPU 100% / 僵尸进程"搏斗的同行

最新文章

随机文章