僵尸进程本身不占内存和cpu,仅占用pid及进程表项;大量堆积会导致fork失败、新进程无法创建,报“resource temporarily unavailable”。

僵尸进程本身不会导致内存溢出,但它暴露了父进程在资源回收上的逻辑漏洞——这个漏洞若出现在长期运行的服务中,可能间接引发内存泄漏甚至系统级故障。
僵尸进程不占内存,但占住关键资源
子进程终止后,内核会立即释放其占用的堆内存、栈空间、打开的文件描述符等绝大部分资源。仅保留一个极小的进程控制块(PCB),通常几十字节,含PID、退出状态、CPU使用时间等元数据。所以它不消耗实际内存,也不吃CPU。
真正危险的是它死死占着一个PID和一个进程表项。Linux默认最大PID数为32768(可通过/proc/sys/kernel/pid_max查看)。一旦僵尸数量接近上限,fork()系统调用就会失败,所有新进程创建请求都会返回Resource temporarily unavailable——此时连ls、ps、日志轮转脚本都可能瘫痪。
为什么“不回收”会演变成系统风险
僵尸不是孤立现象,而是父进程失能的信号:
- 父进程可能陷入死循环或阻塞等待,完全无法响应SIGCHLD信号
- 父进程注册了SIGCHLD处理器,但只调用一次
waitpid(-1, &status, WNOHANG),而实际有多个子进程退出,漏掉回收 - 父进程用阻塞式
wait(),却卡在其他I/O或锁竞争中,迟迟不走到回收逻辑 - 在多线程程序中,只有创建子进程的线程能安全调用
wait(),其他线程调用会失败,而开发者常忽略这点
真正的内存泄漏往往藏在父进程里
很多开发者误以为“只要没僵尸,就没事”,但问题常在别处:
- 父进程虽回收了子进程状态,却未释放自己为子进程分配的缓冲区、连接池对象或共享内存段
- 用
subprocess.Popen启动Python子进程后,仅调用.wait(),却忘记.stdout.close(),导致管道文件描述符持续累积 - C语言中
fork()后,子进程继承了父进程的malloc内存,但父进程若未对子进程生命周期做严格配对管理,容易在错误分支中漏掉free()
两个务实的防御动作
不必等出问题才行动,日常开发和运维中可立刻落地:
- 在父进程中启用WNOHANG + 循环waitpid:确保一次SIGCHLD到来时,能收掉所有已退出的子进程,而非仅一个
-
对关键服务加PID监控告警:比如用
ps -eo stat,pid,ppid | grep '^Z' | wc -l每分钟采集,超过5个就触发通知——这不是看僵尸数量,而是盯父进程是否还在健康工作











