Author : Cyan_RA9
Source : 【卡码笔记】网站
Question : 什么是孤儿进程和僵尸进程,如何处理它们?
【简要回答】
- 孤儿进程(Orphan Process):
- 定义:父进程已终止,子进程仍在运行,这些子进程被称为 孤儿进程,最终会被 init 进程(PID=1)接管并回收。
- 处理方法:通常无需手动处理,由 init 进程自动回收。
- 僵尸进程(Zombie Process):
- 定义:子进程已终止,但父进程未通过
wait()读取其退出状态,导致 PCB 残留。 - 处理方法:父进程调用
wait()或waitpid()主动回收;若父进程无法修改,则终止父进程使其由 init 回收。
- 定义:子进程已终止,但父进程未通过
【详细回答】
- 孤儿进程(Orphan Process):
- 定义:
父进程意外终止(如崩溃、被 kill)先于子进程退出,子进程仍在运行,这些子进程被称为 孤儿进程,操作系统将其父进程重置为 init(PID=1)。 - 产生原因:
父进程未等待子进程结束(如未调用wait())便提前终止。
父进程因错误(如段错误、未处理信号)意外退出。 - 系统影响:
通常对系统无害,但若孤儿进程长时间运行且未正确释放资源(如未关闭文件句柄、未释放共享内存),可能导致资源泄漏。 - 处理方法:
无需手动处理:init 进程会自动接管并调用wait()回收孤儿进程。
- 定义:
- 僵尸进程(Zombie Process):
- 定义:
子进程已终止(通过exit()或信号),但其退出状态未被父进程读取,内核保留其 PCB 直至父进程调用wait()。 - 产生原因:
父进程未调用wait()或waitpid()回收子进程。
父进程未注册 SIGCHLD 信号处理函数,或处理函数未正确回收所有子进程。 - 系统影响:
占用有限的 PID 资源(Linux 默认 PID 上限为 32768),导致系统资源浪费,极端情况下导致新进程无法创建。
残留的 PCB 可能干扰进程监控工具(如 ps、top)的统计信息。 - 处理方法:
① 父进程调用wait()或waitpid()回收子进程资源。
② 若父进程不处理,可终止父进程,由 init 进程接管并回收僵尸进程。
③ 使用信号处理函数(如 SIGCHLD)自动回收子进程。
- 定义:
【知识拓展】
- 僵尸进程示意图如下:
- 僵尸进程案例:Python 异步爬虫系统的“资源泄露”
- 场景: 某公司开发了一个分布式的网页爬虫系统。主程序(父进程)负责调度,每当发现一个新的 URL,就通过
subprocess模块启动一个下载进程(子进程)去抓取内容。 - 发生过程: 程序员在代码中只负责启动子进程,但由于没有写
process.wait()或者没有处理SIGCHLD信号,当下载进程抓取完数据正常退出后,父进程并没有去“收尸”。 - 后果: 由于爬虫任务极多,服务器在运行 24 小时后,
ps -aux发现系统中出现了数千个状态为Z(Zombie) 的进程。最终,服务器报错 "No more processes" 。
- 场景: 某公司开发了一个分布式的网页爬虫系统。主程序(父进程)负责调度,每当发现一个新的 URL,就通过
- 孤儿进程案例:被遗忘的数据库“导出大户”
- 运维人员小王通过 SSH 登录到生产服务器,手动执行了一个超大型的数据库备份脚本:
mysqldump -u root ... > backup.sql。这个任务预计要跑 5 个小时。 - 发生过程: 小王执行完命令后,因为网络抖动,他的 SSH 连接断开了。此时,启动该脚本的父进程(Bash 终端)因为连接断开而自杀了。
- 结果: 这个
mysqldump进程瞬间变成了孤儿进程。幸好 Linux 的内核很聪明,立刻让 PID 为 1 的进程(systemd或init)收养了它,它得以在后台继续跑完。
- 运维人员小王通过 SSH 登录到生产服务器,手动执行了一个超大型的数据库备份脚本: