僵尸进程如何持有资源?Linux下能否复现其资源泄漏?
Linux下僵尸进程的资源持有与资源泄漏问题
然而,僵尸进程也可能保持缓冲区打开,占用内存。僵尸进程还可能持有文件描述符句柄,导致这些文件的存储空间无法被文件系统使用。
核心疑问
- 除了内核进程表中的条目外,僵尸进程还能持有哪些“缓冲区”?它又如何持有文件描述符?
- 已知Linux中进程终止时会关闭所有文件描述符,僵尸进程已终止,那Linux下的僵尸进程为何还能持有资源?是否能通过僵尸进程造成资源泄漏?
- 尝试复现但未成功,如何编写程序在Linux下生成会泄漏资源的僵尸进程?
_Exit/_exit手册说明会关闭所有文件描述符,但strace只看到exit_group没看到close,是否存在其他进程终止方式导致文件描述符未关闭?
复现代码与结果
测试代码
#include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { switch (fork()) { case -1: _Exit(2); case 0: open("/dev/zero", O_RDONLY); _Exit(1); default: sleep(20); _Exit(1); } }
僵尸进程生成结果
$ ps aux | grep a.out kamil 63844 0.0 0.0 2348 992 pts/1 S+ 13:12 0:00 ./a.out kamil 63845 0.0 0.0 0 0 pts/1 Z+ 13:12 0:00 [a.out] <defunct> kamil 63862 0.0 0.0 9492 4436 pts/2 S+ 13:13 0:00 grep a.out
资源检查结果
执行lsof /dev/zero后未发现相关记录,说明子进程的文件描述符已被关闭。
问题解答
1. 僵尸进程的本质与资源持有
Linux下的僵尸进程已经完全终止,内核会回收它的几乎所有资源:包括内存地址空间、打开的文件描述符、缓冲区等。僵尸进程仅保留内核进程表中的一条条目,存储它的退出状态、PID、父进程ID等少量信息,等待父进程调用wait()系列函数读取后彻底清理。
维基百科的描述更适用于部分非Linux的类Unix系统,或者早期Linux版本的特殊场景——现代Linux中,僵尸进程不会持有文件描述符或用户态缓冲区,也就不会造成这类资源泄漏。
2. _Exit/_exit的文件描述符关闭逻辑
strace中看不到close系统调用是因为:内核在处理exit_group时,会自动遍历进程的文件描述符表,关闭所有未关闭的文件描述符,这个过程是内核内部完成的,不会通过用户态的close调用暴露出来。手册页的描述是准确的,只要进程正常调用_Exit/_exit或因信号终止,文件描述符都会被内核关闭。
3. 能否在Linux下通过僵尸进程造成资源泄漏?
常规情况下不行,但存在两种特殊场景可能间接导致类似“资源泄漏”的效果:
- 父进程未及时调用
wait():僵尸进程会占用内核进程表的条目,如果大量生成僵尸进程,会耗尽PID资源(默认PID上限是32768),导致无法创建新进程。这是僵尸进程最常见的资源占用问题,但仅涉及进程表条目,而非文件或内存缓冲区。 - 使用命名空间/容器场景:如果僵尸进程存在于某个PID命名空间中,而该命名空间的init进程(负责回收僵尸)异常退出,那么这些僵尸进程会一直存在,占用命名空间内的PID资源,直到命名空间被销毁。
4. 不存在能持有文件描述符的Linux僵尸进程
无论用哪种进程终止方式(正常退出、信号杀死),内核都会在进程进入僵尸状态前回收所有文件描述符、内存缓冲区等资源。所以无法编写程序让Linux下的僵尸进程持有文件描述符或其他资源——你的测试结果符合Linux的实际行为。
内容的提问来源于stack exchange,提问作者KamilCuk
相关产品推荐
相关产品推荐

