0

0

Linux 僵尸进程是如何产生的?

舞夢輝影

舞夢輝影

发布时间:2026-01-25 16:22:02

|

708人浏览过

|

来源于php中文网

原创

僵尸进程产生的主要原因是父进程未调用wait()或waitpid()回收子进程退出状态,导致子进程残留task_struct并卡在Z状态;常见场景包括父进程忽略SIGCHLD、双fork隔离失败、父进程崩溃等。

linux 僵尸进程是如何产生的?

子进程退出后父进程没调用 wait()waitpid()

这是最常见、最直接的产生原因。子进程调用 exit() 后,内核会保留它的 task_struct 和退出状态(如退出码、CPU 时间等),但释放其他资源(内存、文件描述符等)。这部分残留信息必须由父进程显式读取并清理——通过 wait()waitpid() 系统调用完成。如果父进程完全不调用,或者只在某条分支里调用(比如漏了错误处理路径),子进程就会卡在 Z(zombie)状态。

  • 现象:用 ps aux | grep 'Z'ps -eo stat,ppid,pid,cmd | grep '^Z' 能看到状态列为 Z 的进程
  • 注意:kill -9 对僵尸进程无效——它已经死了,只是没被“收尸”
  • 风险:每个僵尸进程占用一个 PID 和少量内核内存;PID 耗尽(默认上限 32767)会导致新进程无法创建

父进程忽略 SIGCHLD 信号但未设为 SIG_IGN

当子进程终止,内核默认向父进程发送 SIGCHLD。如果父进程注册了自定义信号处理函数(比如用 signal(SIGCHLD, handler)),但 handler 里没调用 waitpid(-1, &status, WNOHANG),或者只调用了一次却有多个子进程退出,就可能漏收——尤其在高并发 fork 场景下。更隐蔽的是:有些代码写了 signal(SIGCHLD, SIG_DFL) 或干脆没处理,结果信号被忽略,而内核又不会自动回收,于是僵死。

  • 正确做法是:要么设为 SIG_IGNsignal(SIGCHLD, SIG_IGN)),让内核代劳回收;要么在 handler 中循环调用 waitpid() 直到返回 -1 + errno == ECHILD
  • 陷阱:wait() 是阻塞的,waitpid(-1, ..., WNOHANG) 才是非阻塞且可轮询多个子进程的

双 fork 隔离失败或误用

“两次 fork” 是经典规避方案:父进程 fork 出子进程 A,A 再 fork 出孙进程 B 后立即 exit();B 变成孤儿进程,被 init(PID 1)接管,而 init 会自动 wait 所有子进程,所以 B 不会变僵尸。但这个技巧容易用错:

微客农场复利系统
微客农场复利系统

微客农场复利系统是一个以php+mysql进行开发的php直销系统源码。软件特点:一、自动结算宠物产生的金币由于网页是触发型,需要有触发才能执行某种功能:比如点击按钮,才能执行某种功能;刷新页面才能执行某种功能……在没有触发的情况下,是不会自动执行程序代码的。而宠物将每天产生金币,这个必须是:网页自动执行和结算。解决方案有两个:1、购买服务器,在服务器里

下载
  • 子进程 A 必须在 fork B 后立刻 exit(),不能做任何可能阻塞或崩溃的操作,否则 A 自己可能变成僵尸
  • 如果父进程在 A exit() 前就退出,A 和 B 都可能被 init 接管——看似安全,但逻辑已脱离设计预期
  • Go/Python 等语言的运行时可能自带子进程管理,盲目套用双 fork 可能和 runtime 冲突

父进程崩溃或长期不响应导致“收尸”中断

即使父进程原本写了正确的 wait 逻辑,若它在子进程退出后、执行到 wait 前发生段错误、被 kill -9 或死锁,那已退出的子进程就永远卡在僵尸态。此时唯一出路是让 init 接管——但前提是父进程先挂掉。而如果父进程是守护进程(如 nginx worker、systemd service),它往往设计为永不停止,这就导致僵尸进程持续累积。

  • 验证方法:ps -o pid,ppid,stat,comm -C your_parent_cmd 查看父进程是否存活,再对照其子进程的 PPID 是否指向它
  • 临时缓解:杀掉父进程(kill -9 ),init 通常会在几秒内回收其遗留的僵尸子进程
  • 根本解法:在父进程代码中确保所有退出路径(包括信号处理、异常分支)都覆盖 wait 或设 SIG_IGN

真正麻烦的不是单个僵尸进程,而是父进程逻辑里藏着条件竞争或信号处理盲区——它可能在 99% 的情况下正常工作,直到某次高负载或特定信号序列触发漏收。查 /proc//status 里的 State: ZPPid: 字段,比盯着 top 的 zombie 计数更有诊断价值。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

774

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

684

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

767

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

719

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1425

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

570

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

751

2023.08.11

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

44

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.8万人学习

Git 教程
Git 教程

共21课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号