pid=1 不回收 zombie 是因它们并非孤儿进程,而是父进程存活却未调用 wait();常见原因包括父进程阻塞、忽略或屏蔽 SIGCHLD,或多线程中信号处理不当。
zombie 进程的父进程是 pid=1,为什么没被回收?
pid=1 的 systemd(或传统 init)本应自动收尸所有孤儿 zombie 进程,但实际中仍见大量 zombie 存在,说明这些进程**并非真正孤儿**——它们的父进程仍是某个用户态进程,只是该父进程没有调用 wait() 或 waitpid() 获取子进程退出状态。pid=1 只接管“父进程已退出”的孤儿进程,不干预“父进程还活着但怠惰”的情况。
常见诱因包括:
- 父进程阻塞在信号处理、锁、I/O 或死循环中,无法响应
SIGCHLD - 父进程显式忽略了
SIGCHLD(如调用signal(SIGCHLD, SIG_IGN)),且未手动wait - 父进程使用了
sigprocmask()屏蔽了SIGCHLD,导致信号积压未被投递 - 多线程程序中,
SIGCHLD被发给非预期线程,而该线程未设置sigwait()或 handler
如何定位真正的父进程和它是否在等待子进程?
别只看 ps aux | grep 'Z',重点查 PPID 和父进程当前状态:
- 执行
ps -eo pid,ppid,stat,comm,args | awk '$3 ~ /Z/ {print $0}',确认每个 zombie 的PPID - 对每个可疑
PPID,运行ps -o pid,ppid,state,wchan:20,comm -p $PPID,观察其state(R/S/D/Z)和wchan(等待内核函数,如do_wait表示正在 wait,ep_poll或空则可能卡住) - 用
strace -p $PPID -e trace=wait4,waitpid,waitid,rt_sigreturn 2>&1 | head -20看父进程是否在调用 wait 类系统调用(注意:生产环境慎用,可能影响性能)
若父进程 state == S 且 wchan 是 pipe_wait、ep_poll 或 hrtimer_nanosleep,大概率它正阻塞在别的地方,没轮到处理子进程退出。
systemd 服务中 fork 出的子进程变成 zombie 怎么办?
systemd 默认以 Type=simple 启动服务,此时主进程即为 pid=1 的子进程;若它 fork 出子进程又不 wait,zombie 就会堆积。正确做法是: