孤儿进程和僵尸进程

2023-11-20

作者:华清远见讲师

前段时间,由于研究经典面试题,把孤儿进程和僵尸进程也总结了一下。

我们有这样一个问题:孤儿进程和僵尸进程,怎么产生的?有什么危害?怎么去预防?

下面是针对此问题的总结与概括。

一.产生的原因

1) 一般进程

正常情况下:子进程由父进程创建,子进程再创建新的进程。父子进程是一个异步过程,父进程永远无法预测子进程的结束,所以,当子进程结束后,它的父进程会调用wait()或waitpid()取得子进程的终止状态,回收掉子进程的资源。

2)孤儿进程

孤儿进程:父进程结束了,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程(father died)。子进程的资源由init进程(进程号PID = 1)回收。

3)僵尸进程

僵尸进程:子进程退出了,但是父进程没有用wait或waitpid去获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵死进程。

二.问题危害

注意:unix提供了一种机制保证父进程知道子进程结束时的状态信息。

这种机制是:在每个进程退出的时候,内核会释放所有的资源,包括打开的文件,占用的内存等。但是仍保留一部分信息(进程号PID,退出状态,运行时间等)。直到父进程通过wait或waitpid来取时才释放。

但是这样就会产生问题:如果父进程不调用wait或waitpid的话,那么保留的信息就不会被释放,其进程号就会被一直占用,但是系统所能使用的进程号是有限的,如果大量产生僵死进程,将因没有可用的进程号而导致系统无法产生新的进程,这就是僵尸进程的危害

孤儿进程是没有父进程的进程,它由init进程循环的wait()回收资源,init进程充当父进程。因此孤儿进程并没有什么危害。

补充:任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程的数据结构,等待父进程去处理。如果父进程在子进程exit()之后,没有及时处理,出现僵尸进程,并可以用ps命令去查看,它的状态是“Z”。

三.解决方案

1)kill杀死元凶父进程(一般不用)

严格的说,僵尸进程并不是问题的根源,罪魁祸首是产生大量僵死进程的父进程。因此,我们可以直接除掉元凶,通过kill发送SIGTERM或者SIGKILL信号。元凶死后,僵尸进程进程变成孤儿进程,由init充当父进程,并回收资源。

或者运行:kill -9 父进程的pid值、

2)父进程用wait或waitpid去回收资源(方案不好)

父进程通过wait或waitpid等函数去等待子进程结束,但是不好,会导致父进程一直等待被挂起,相当于一个进程在干活,没有起到多进程的作用。

3)通过信号机制,在处理函数中调用wait,回收资源

通过信号机制,子进程退出时向父进程发送SIGCHLD信号,父进程调用signal(SIGCHLD,sig_child)去处理SIGCHLD信号,在信号处理函数sig_child()中调用wait进行处理僵尸进程。什么时候得到子进程信号,什么时候进行信号处理,父进程可以继续干其他活,不用去阻塞等待。

例子1:

#include

#include

#include

#include

#include

static void sig_child(int signo);

int main()

{

pid_t pid;

//创建捕捉子进程退出信号

signal(SIGCHLD,sig_child);

pid = fork();

if (pid < 0)

{

perror("fork error:");

exit(1);

}

else if (pid == 0)

{

printf("I am child process,pid id %d.I am exiting.\n",getpid());

exit(0);

}

printf("I am father process.I will sleep two seconds\n");

//等待子进程先退出

sleep(2);

//输出进程信息

system("ps -o pid,ppid,state,tty,command");

printf("father process is exiting.\n");

return 0;

}

static void sig_child(int signo)

{

pid_t pid;

int stat;

//处理僵尸进程

while ((pid = waitpid(-1, &stat, WNOHANG)) >0)

printf("child %d terminated.\n", pid);

}

4)fork两次

fork两次,父进程fork一个子进程,子进程在fork出一个孙子进程,然后子进程立马退出,并由父进程去wait回收,这个过程不需要等待,然后父进程可以去干其他的活。孙子进程因为子进程退出会成为孤儿进程,那它可以由init充当父进程,并回收。这样父进程和孙子进程就可以同时干活,互不影响,就实现了多进程。

例子2:

#include

#include

#include

#include

int main()

{

pid_t pid;

//创建第一个子进程

pid = fork();

if (pid < 0)

{

perror("fork error:");

exit(1);

}

//第一个子进程

else if (pid == 0)

{

//子进程再创建子进程

printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());

pid = fork();

if (pid < 0)

{

perror("fork error:");

exit(1);

}

//第一个子进程退出

else if (pid >0)

{

printf("first procee is exited.\n");

exit(0);

}

//第二个子进程

//睡眠3s保证第一个子进程退出,这样第二个子进程的父亲就是init进程里

sleep(3);

printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());

exit(0);

}

//父进程处理第一个子进程退出

if (waitpid(pid, NULL, 0) != pid)

{

perror("waitepid error:");

exit(1);

}

exit(0);

return 0;

}

四.补充测试程序

1)孤儿进程测试程序

#include

#include

#include

#include

int main()

{

pid_t pid;

//创建一个进程

pid = fork();

//创建失败

if (pid < 0)

{

perror("fork error:");

exit(1);

}

//子进程

if (pid == 0)

{

printf("I am the child process.\n");

//输出进程ID和父进程ID

printf("pid: %d\tppid:%d\n",getpid(),getppid());

printf("I will sleep five seconds.\n");

//睡眠5s,保证父进程先退出

sleep(5);

printf("pid: %d\tppid:%d\n",getpid(),getppid());

printf("child process is exited.\n");

}

//父进程

else

{

printf("I am father process.\n");

//父进程睡眠1s,保证子进程输出进程id

sleep(1);

printf("father process is exited.\n");

}

return 0;

}

2)僵尸进程测试程序1

int main()

{

pid_t pid;

pid = fork();

if (pid < 0)

{

perror("fork error:");

exit(1);

}

else if (pid == 0)

{

printf("I am child process.I am exiting.\n");

exit(0);

}

printf("I am father process.I will sleep two seconds\n");

//等待子进程先退出

sleep(2);

//输出进程信息

system("ps -o pid,ppid,state,command");

printf("father process is exiting.\n");

return 0;

}

3)僵尸进程测试程序2

#include

#include

#include

#include

int main()

{

pid_t pid;

//循环创建子进程

while(1)

{

pid = fork();

if (pid < 0)

{

perror("fork error:");

exit(1);

}

else if (pid == 0)

{

printf("I am a child process.\nI am exiting.\n");

//子进程退出,成为僵尸进程

exit(0);

}

else

{

//父进程休眠20s继续创建子进程

sleep(20);

continue;

}

}

return 0;

}

4)僵尸进程测试程序2--测试效果

运行可执行程序显示:

I am a child process.

I am exiting.

I am a child process.

I am exiting.

I am a child process.

I am exiting.

I am a child process.

I am exiting.

I am a child process.

I am exiting.

I am a child process.

I am exiting.

Killed

开另外一个终端:

运行:

ps -a -o pid,ppid,state,cmd

显示:(状态Z代表僵尸进程)

S PID PPID CMD

S 3213 2529 ./pid1

Z 3214 3213 [pid1]

Z 3215 3213 [pid1]

Z 3219 3213 [pid1]

Z 3220 3213 [pid1]

Z 3221 3213 [pid1]

R 3223 3104 ps -a -o state,pid,ppid,cmd

用第一种方法,解决僵尸进程,杀死其父进程

运行:kill -9 3213

注意:僵尸进程无法用kill直接杀死,如kill -9 3214,再用上面命令去查看进程状态,发现3214进程还在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

孤儿进程和僵尸进程 的相关文章

随机推荐

  • 【模型剪枝】——开源项目总结

    修剪是一种常用的压缩神经网络模型的技术 修剪方法探索模型权重 参数 中的冗余 并尝试删除 修剪冗余和非关键权重 冗余元素从模型中修剪 它们的值归零 我们确保它们不参与反向传播过程 pytorch pruning https github c
  • 设置定时任务为每天凌晨2点执行和每小时执行一次?

    每天凌晨2点 0 0 2 和每天隔一小时 0 1 例1 每隔5秒执行一次 5 例2 每隔5分执行一次 0 5 在26分 29分 33分执行一次 0 26 29 33 例3 每天半夜12点30分执行一次 0 30 0 注意日期域为0不是24
  • axure9怎么让页面上下滑动_Axure动态面板(上下左右滑动页面)

    手机端交互中 页面的上下左右滑动是常用的交互形态 今天给大家分享一下如何使用Axure来进行模拟 这里使用动态面板来实现 如果对动态面板不是很了解的同学 请查看专栏里的 动态面板入门教程 先看效果 开工之前我们我们先分析一下 滑动效果的用处
  • 利用Android Lost通过互联网或短信远程控制安卓设备

    利用Android Lost通过互联网或短信远程控制安卓设备 作者 Jack Wallen 杰克 瓦伦翻译 PurpleEndurer 2014 11 15第1版 使用智能手机要考虑的一个至关重要的因素是安全性 当然 安全问题不仅仅存在于平
  • java springboot -- MultipartFile -图片上传到远程服务器上

    新增文件 param file return private boolean saveFile MultipartFile file try 文件保存路径 String filePath A merchant 映射的地址 String fi
  • Springboot+vue+hadoop+java图书个性化推荐系统

    前台首页功能模块 3 1首页 图书个性化推荐系统 在前台首页可以查看首页 图书信息 好书推荐 留言反馈 个人中心 后台管理等内容 如图 3 2图书信息 在图书信息页面通过查看图书编号 图书名称 图书类别 图片 作者 出版社 版次 数量 点击
  • 背单词(持续更新)

    文章目录 星火雅思周计划 229 复习 考研 352 353 职场俚语 1 2 7分 1 2 3 4 5 6 7 8 haochi fun 1 2 GRE 1 2 托福 249 247 248 245 246 243 244 241 242
  • 3WebGL shader准备工具

    VSCode安装 VSCode 全称 Visual Studio Code 是一款由微软开发且跨平台的免费源代码编辑器 该软件支持语法高亮 代码自动补全 又称 IntelliSense 代码重构 查看定义功能 并且内置了命令行工具和 Git
  • Unity保存图片到相册

    Unity保存图片到Android相册 Java 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  • ESXI 7.0 版本配置N卡显卡直通

    ESXI 7 版本配置N卡显卡直通 前因 ESXI版本太新 网上啥参考资料没有 显卡直通各种问题 虚机一装显卡驱动就直接把宿主机直接整挂了 于是各种查资料 各种尝试 终于搞定直通问题 配置 名称 版本 服务器 DELL R720 ESXI
  • MySQL中的DML、DDL、DCL到底是什么玩意呢?

    个人主页 极客小俊 作者简介 web开发者 设计师 技术分享博主 希望大家多多支持一下 我们一起进步 如果文章对你有帮助的话 欢迎评论 点赞 收藏 加关注 引言 一直以来 很多人分不清这三个东西到底是什么简称 代表什么 至在面试中遇到可能会
  • nginx的location、root、alias指令用法和区别

    亲测可用 若有疑问请私信 nginx指定文件路径有两种方式root和alias 指令的使用方法和作用域 root 语法 root path 默认值 root html 配置段 http server location if alias 语法
  • Arduino动手做(48)---三轴ADXL345模块

    37款传感器与模块的提法 在网络上广泛流传 其实Arduino能够兼容的传感器模块肯定是不止37种的 鉴于本人手头积累了一些传感器和模块 依照实践 动手试试 出真知的理念 以学习和交流为目的 这里准备逐一做做实验 不管能否成功 都会记录下来
  • 第十二届蓝桥杯 2021年省赛真题 (Java 大学C组) 第二场

    蓝桥杯 2021年省赛真题 Java 大学C组 第二场 A 浮点数 B 求余 C 双阶乘 D 格点 E 整数分解 F 3 的倍数 G 特殊年份 H 小平方 I 完全平方数 J 负载均衡 A 浮点数 题目 问题描述 IEEE 754 规定一个
  • 关于HTML基本标签及结构详解

    本文主要介绍了HTML基本标签及结构详解 本文给大家介绍的非常详细 对大家的学习或工作具有一定的参考借鉴价值 需要的朋友可以参考下 1 HTML概述 1 HTML 超文本标记语言 是一种标识性语言 非编程语言 不能使用逻辑运算 通过标签将网
  • 吴恩达 deeplearning.ai课程-卷积神经网络 (2)深度卷积模型-实例探究

    参考来源 https blog csdn net red stone1 article details 78769236 https blog csdn net koala tree article details 78531398 有关C
  • python自动化笔记(九)文件操作

    文件的打开 file open test txt w encoding utf 8 参数 文件名 访问模式 write 默认为read file write hello python 删除原有内容 并写入 ret file read 读取文
  • Flutter使用百度定位经纬度数据正常,详细地址为null

    Flutter使用百度定位经纬度数据正常 详细地址为null 更新至2021 09 07 一 问题 1 使用百度定位 插件返回的数据中经纬度有正常值 其他地址信息都为null 二 分析原因 1 在wifi或移动网络没有 不好的情况下 会出现
  • 自动注册appleid

    1 通过猴油注册脚本 用js填写表单 问题 由于apple官网采用了自己封装的mvvm框架 如果只是赋值的话 还不能把视图上的数据更新到model上 必须触发一下表单元素的input事件或者change事件完成model的更新 CSP网站安
  • 孤儿进程和僵尸进程

    作者 华清远见讲师 前段时间 由于研究经典面试题 把孤儿进程和僵尸进程也总结了一下 我们有这样一个问题 孤儿进程和僵尸进程 怎么产生的 有什么危害 怎么去预防 下面是针对此问题的总结与概括 一 产生的原因 1 一般进程 正常情况下 子进程由