python僵尸进程产生的原因
发布时间 - 2026-01-11 02:26:25 点击率:次在 unix 或 unix-like 的系统中,当一个子进程退出后,它就会变成一个僵尸进程,如果父进程没有通过 wait 系统调用来读取这个子进程的退出状态的话,这个子进程就会一直维持僵尸进程状态。

Zombie process - Wikipedia 中是这样描述的:
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution (via the exit system call) but still has an entry in the process table: it is a process in the "Terminated state". This occurs for child processes, where the entry is still needed to allow the parent process to read its child's exit status: once the exit status is read via the wait system call, the zombie's entry is removed from the process table and it is said to be "reaped". A child process always first becomes a zombie before being removed from the resource table. In most cases, under normal system operation zombies are immediately waited on by their parent and then reaped by the system – processes that stay zombies for a long time are generally an error and cause a resource leak.
并且僵尸进程无法通过 kill 命令来清除。
本文将探讨如何手动制造一个僵尸进程以及清除僵尸进程的办法。
手动制造一个僵尸进程
为了便于后面讲解清除僵尸进程的方法,我们使用日常开发中经常使用的 multiprocessing 模块来制造僵尸进程(准确的来说是制造一个长时间维持僵尸进程状态的子进程):
$ cat test_a.py
from multiprocessing import Process, current_process
import logging
import os
import time
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)-15s - %(levelname)s - %(message)s'
)
def run():
logging.info('exit child process %s', current_process().pid)
os._exit(3)
p = Process(target=run)
p.start()
time.sleep(100)
测试:
$ python test_a.py & [1] 10091 $ 2017-07-20 21:28:14,792 - INFO - exit child process 10106 $ ps aux |grep 10106 mozillazg 10126 0.0 0.0 2434836 740 s006 R+ 0:00.00 grep 10106 mozillazg 10106 0.0 0.0 0 0 s006 Z 0:00.00 (Python)
可以看到,子进程 10091 变成了僵尸进程。
既然已经可以控制僵尸进程的产生了,那我们就可以进入下一步如何清除僵尸进程了。
清除僵尸进程有两种方法:
•第一种方法就是结束父进程。当父进程退出的时候僵尸进程随后也会被清除。
• 第二种方法就是通过 wait 调用来读取子进程退出状态。我们可以通过处理 SIGCHLD 信号,在处理程序中调用 wait 系统调用来清除僵尸进程。
处理 SIGCHLD 信号
子进程退出时系统会向父进程发送 SIGCHLD 信号,父进程可以通过注册 SIGCHLD 信号处理程序,在信号处理程序中调用 wait
系统调用来清理僵尸进程。 $ cat test_b.py
import errno
from multiprocessing import Process, current_process
import logging
import os
import signal
import time
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)-15s - %(levelname)s - %(message)s'
)
def run():
exitcode = 3
logging.info('exit child process %s with exitcode %s',
current_process().pid, exitcode)
os._exit(exitcode)
def wait_child(signum, frame):
logging.info('receive SIGCHLD')
try:
while True:
# -1 表示任意子进程
# os.WNOHANG 表示如果没有可用的需要 wait 退出状态的子进程,立即返回不阻塞
cpid, status = os.waitpid(-1, os.WNOHANG)
if cpid == 0:
logging.info('no child process was immediately available')
break
exitcode = status >> 8
logging.info('child process %s exit with exitcode %s', cpid, exitcode)
except OSError as e:
if e.errno == errno.ECHILD:
logging.error('current process has no existing unwaited-for child processes.')
else:
raise
logging.info('handle SIGCHLD end')
signal.signal(signal.SIGCHLD, wait_child)
p = Process(target=run)
p.start()
while True:
time.sleep(100)
效果:
$ python test_b.py & [1] 10159 $ 2017-07-20 21:28:56,085 - INFO - exit child process 10174 with exitcode 3 2017-07-20 21:28:56,088 - INFO - receive SIGCHLD 2017-07-20 21:28:56,089 - INFO - child process 10174 exit with exitcode 3 2017-07-20 21:28:56,090 - ERROR - current process has no existing unwaited-for child processes. 2017-07-20 21:28:56,090 - INFO - handle SIGCHLD end $ ps aux |grep 10174 mozillazg 10194 0.0 0.0 2432788 556 s006 R+ 0:00.00 grep 10174
可以看到,子进程退出变成僵尸进程后,系统给父进程发送了 SIGCHLD 信号,我们在 SIGCHLD 信号的处理程序中通过 os.waitpid 调用 wait 系统调用后阻止了子进程一直处于僵尸进程状态,从而实现了清除僵尸进程的效果。
# python
# 僵尸进程
# 多进程
# 僵尸
# 判断僵尸进程
# 就会
# 可以看到
# 种方法
# 信号处理
# 也会
# 是这样
# 长时间
# 我们可以
# 可以通过
# 如果没有
# 有两种
# 送了
# 会向
# 就可以
# 变成了
# 实现了
# 产生了
# generally
# error
# long
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Swift中switch语句区间和元组模式匹配
佛山网站制作系统,佛山企业变更地址网上办理步骤?
Android仿QQ列表左滑删除操作
EditPlus中的正则表达式 实战(1)
Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试
如何在 Pandas 中基于一列条件计算另一列的分组均值
Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
在centOS 7安装mysql 5.7的详细教程
Laravel如何实现多对多模型关联?(Eloquent教程)
利用vue写todolist单页应用
深圳网站制作的公司有哪些,dido官方网站?
如何快速完成中国万网建站详细流程?
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
如何在IIS服务器上快速部署高效网站?
如何获取免费开源的自助建站系统源码?
Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制
Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境
高端建站如何打造兼具美学与转化的品牌官网?
,怎么在广州志愿者网站注册?
Laravel如何使用查询构建器?(Query Builder高级用法)
Laravel如何实现用户密码重置功能?(完整流程代码)
如何在VPS电脑上快速搭建网站?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】
Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】
微信小程序 HTTPS报错整理常见问题及解决方案
如何在景安服务器上快速搭建个人网站?
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
如何快速生成凡客建站的专业级图册?
Android自定义控件实现温度旋转按钮效果
Win11怎么设置默认图片查看器_Windows11照片应用关联设置
Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载
如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
如何在阿里云域名上完成建站全流程?
微信小程序 闭包写法详细介绍
如何注册花生壳免费域名并搭建个人网站?
浅析上传头像示例及其注意事项
高端企业智能建站程序:SEO优化与响应式模板定制开发
桂林网站制作公司有哪些,桂林马拉松怎么报名?
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏
香港服务器WordPress建站指南:SEO优化与高效部署策略
Laravel如何使用Sanctum进行API认证?(SPA实战)
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
JS中对数组元素进行增删改移的方法总结
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】

