僵尸进程是已终止但未被父进程回收的子进程残留条目,仅保留在进程表中,状态标记为z,不占cpu或内存,只维持pid、退出状态等少量内核数据;其存在直至父进程调用wait/waitpid、父进程退出后由init接管回收,或系统重启。

僵尸进程本身没有生命周期,它只是已终止但尚未被父进程回收的进程残留条目,存在于进程表中,不占用CPU或内存资源,只保留少量内核数据结构(如PID、退出状态等)。
什么是僵尸进程
当子进程调用 exit() 或收到终止信号后,内核不会立即释放其进程描述符;只要父进程尚未调用 wait() 或 waitpid() 获取其退出状态,该子进程就处于僵尸状态(Z状态)。此时 ps 命令中显示为 Z。
如何模拟僵尸进程
- 编写一个父进程 fork 出子进程,子进程立即 exit,父进程 sleep 不调用 wait
- 运行后用 ps aux | grep 'Z' 或 ps -eo pid,ppid,stat,comm | grep 'Z' 观察 Z 状态进程
- 可配合 strace -f 跟踪父进程系统调用,确认未执行 wait 类系统调用
僵尸进程何时消失
僵尸进程会持续存在,直到以下任一条件满足:
- 父进程显式调用 wait()/waitpid() 获取子进程退出状态
- 父进程自身退出,此时 init 进程(PID=1)自动收养孤儿进程,并负责 wait 清理
- 系统重启(极端情况,非正常清理方式)
避免僵尸进程的关键点
- 父进程应始终处理子进程退出:通过 signal(SIGCHLD, handler) 捕获 CHLD 信号,在 handler 中循环 waitpid(-1, &status, WNOHANG)
- 若父进程不关心子进程退出码,可用 fork + setsid + _exit 组合使子进程脱离父进程上下文(适用于守护进程场景)
- 避免忽略 SIGCHLD 信号,默认行为会导致僵尸积累;显式忽略(signal(SIGCHLD, SIG_IGN))在 Linux 上可自动清理,但不具备可移植性
不复杂但容易忽略。关键不在“测试生命周期”,而在理解它本质是回收机制缺失的瞬时现象——它不会自己变化,只等父进程或 init 来收尾。











