目录

  • 僵尸进程
    • 解决方式
      • 父进程阻塞调用wait()
      • 父进程非阻塞调用waitpid()
      • SIGCHLD信号
      • SIG_IGN信号

僵尸进程

我们知道linux下进程有种状态叫做僵尸状态;

原因是父进程fork()出来的子进程结束之后,内核会给父进程发送一个SIGCHLD信号,;

这个SIGCHLD信号的作用是及时通知父进程子进程的退出让父进程通过一系列手段将他回收;
回收的意义:
1.避免僵尸进程的产生,内存泄漏
2.且使得父进程能拿到子进程的退出状态,进行相应处理

如果父进程没有忽略这个信号(设置SIG_IGN),也没有等待(wait)子进程,而且结束的也比子进程晚(不能托管被init1号进程领养),并且也没有handler捕捉这个信号,那子进程就会进入僵尸状态; 维护者自己的task_struct开销,这也是一种内存泄露;

解决方式

对于这个问题有已下几种解决方式:

父进程阻塞调用wait()

#include <sys/types.h> /* 提供类型pid_t的定义 */#include <sys/wait.h>pid_t wait(int *status)//status 输出型参数,可以拿到子进程退出的状态码,不关心的话设置NULL即可;

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

  • 显然wait的调用是非常不合理的,阻塞时等待会让父进程干不了别的事情;

父进程非阻塞调用waitpid()

#include <sys/types.h> /* 提供类型pid_t的定义 */#include <sys/wait.h>pid_t waitpid(pid_t pid,int *status,int options)//pid设置为-1代表等待任意一个进程, options设置为WNOHANG 即便无子进程退出,它也会立即返回,不会像wait那样永远等下去!

根据源码的观察,不难发现,其实wait就是waitpid的一种封装:

static inline pid_t wait(int * wait_stat){return waitpid(-1,wait_stat,0);//-1等待任意进程退出,0代表什么都不设置,阻塞式等待!}
  • waitpid虽然不会阻塞时等待,但是也需要占用cpu资源,定期的轮训waitpid看看有没有子进程处于僵尸状态,以便将他回收,也是有一定开销的

SIGCHLD信号

其实我们的子进程每次终止时内核都会给父进程发送一个SIGCHLD信号, 如果父进程没有处理这个信号,也没有等待(wait)子进程,那他就会进入僵尸状态;

既然这样,我们可以用signal()函数+waitpid()接口处理一下这个信号,答到一个子进程退出之后,主动通知父进程将其回收的异步通知作用!(显然效率是比父进程主动wait和waitpid这种同步处理高!)

#include <signal.h>
typedef void (*sighandler_t)(int);//简单来说,sighandler_t是一个无返回值,参数为一个int的函数指针sighandler_t signal(int signum, sighandler_t handler);
  • signum参数指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号(SIGKILL是kill -9命令,如果把它改了,有可能一个进程我们真的就无法“杀死终止”了)
  • handler参数中的int参数就是捕获到的对应信号的int编码,linux用kill -l命令可以查看:

参考代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/wait.h>void handler(int sig)
{pid_t id;while((id = waitpid(-1, NULL, WNOHANG)) > 0)//while循环处理需要回收的子进程printf(“wait child success : %d\n”, id);
}int main()
{signal(SIGCHLD, handler);//指定SIGCHLD信号来到时,需要被handler函数处理pid_t ret = fork();if(ret == 0){printf(“child : %d\n”, getpid());sleep(3);exit(0);//子进程退出,并给父进程发送SIGCHLD信号和0这个退出码}while(1){printf(“father process is doing some thing!\n”);sleep(1);}return 0;
}

注意,handler中使用while循环处理回收任务的原因是:SIGCHILD是个非可靠信号

一个父进程可能有很多子进程,如果多个子进程同时退出,SIGCHILD会出现信号丢失(只存在1个)。如果用if处理,也就只处理一个子进程。剩下的子进程也就变成了僵尸进程!

因此我们发现有子进程退出,就用while循环来处理,如果恰好多个子进程退出,即便信号丢失,我们也能while通过waitpid的返回值不断释放他们,即便只有一个子进程退出,第二次循环waitpid会返回0,我们也会跳出循环!

有点像mutex+cond需要while处理虚假唤醒,参考我的这篇文章

SIG_IGN信号

我们都知道,解决僵尸进程还有一个方式,就是让他变为“孤儿进程”,也就是init1号进程领养托管,进而释放这个子进程的资源!

除了让父进程退出的比子进程早之外,我们可以通过如下操作,将SIGCHLD信号的处理方式设置为SIG_IGN–>忽略,这样代表父进程忽视了这个信号,子进程相当于被弃养,会被init1号进程领养

signal(SIGCHLD, SIG_IGN);

这样可让内核把僵尸子进程转交给init1号进程去处理释放,省去了父进程wait这个子进程的麻烦;

这个小技巧常常被用于提升并发服务器的性能!

Linux解决僵尸进程的几种方式,SIGCHLD信号设置SIG_IGN处理方式等相关推荐

  1. 【Linux】SIGCHLD信号解决僵尸进程问题

    1. 基本信息 SIGCHLD信号产生的条件: 子进程终止时 子进程接收到SIGSTOP信号停止时 子进程处在停止态,接受到SIGCONT后唤醒时 以上三种条件都会给父进程发送SIGCHLD信号,父进 ...

  2. Linux的僵尸进程及其解决方法(转)

    Linux的僵尸进程及其解决方法 摘要: Linux的僵尸进程及其解决方法 1. 产生原因: 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将 ...

  3. linux下僵尸进程(<defunct>进程)的产生与避免

    一.什么是僵尸进程 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程.当用ps命令观察进程的执行状态时,看到这些进程的状态栏为 ...

  4. linux 识别僵尸进程,Linux上寻找并杀死僵尸进程

    转载: http://blog.csdn.net/shanzhizi/article/details/47320595 linux服务器上,多少会出现一些僵尸进程,下面介绍如何快速寻找和消灭这些僵尸进 ...

  5. linux六种进程状态,Linux操作系统中进程的七种状态

    Linux操作系统中进程的七种状态 发布时间:2018-05-07 20:43, 浏览次数:741 , 标签: Linux 1 Linux中进程的七种状态(1)R运行状态(runing):并不意味着进 ...

  6. linux系统调用劫持隐藏进程,linux 下隐藏进程的一种方法及遇到的坑

    前言 1.本文所用到的工具在 https://github.com/gianlucaborello/libprocesshider 可以下载 2.思路就是利用 LD_PRELOAD 来实现系统函数的劫 ...

  7. linux 批量删除进程的两种方法

    linux批量删除进程的两种方法 介绍两种方法.要kill的进程都有共同的字串. [plain]  kill -9 `ps -ef |grep xxx|awk '{print $2}' `    ki ...

  8. 查询php僵死进程,linux查找僵尸进程(zombie进程)

    首先,我们可以用top命令来查看服务器当前是否有僵尸进程,可以看到第二行行尾有个 0 zombie,如果数字大于0,那么意味着服务器当前存在有僵尸进程 可以用ps和grep命令寻找僵尸进程 ps -A ...

  9. linux杀死僵尸进程

    linux杀死僵尸进程 输入ps查看所有进程的pid 输入kill -9 pid杀死目标进程

最新文章

  1. 机器学习:论相关(二)
  2. 太强了!Python 开发桌面小工具,让代码替我们干重复的工作!
  3. Linux第一条指令地址,arm-linux 启动代码分析——stage1 (1)
  4. react销毁方法钩子0_React钩子:使用React状态的新方法
  5. 好看的a标签按钮样式
  6. LeetCode 263. Ugly Number
  7. 自己做了个微信小程序
  8. 通过改变浏览器Cookie切换当前网站马甲
  9. 产品经理会用到的常用术语大全
  10. XTUOJ-1281-Cute String
  11. 凯撒密码加密算法python_密码学初探:隐藏信息的艺术——区块链技术引卷之十一...
  12. W25Q128FV译文(一)
  13. 2022.8.11SAP目前为止学习总结
  14. 硬笔书法的产生与兴起
  15. python爬取网易云音乐飙升榜音乐_python爬取网易云音乐热歌榜 python爬取网易云音乐热歌榜实例代码...
  16. uc 7.20.0.1009 注册码
  17. Linux 下实现虚拟专用网(PPTP)
  18. 表必备三字段:id, gmt_create, gmt_modified
  19. dovecot主要配置文件
  20. mysql定时备份数据库-linux

热门文章

  1. 物联网毕业设计 - 基于STM32的轮足两用可变形环境感知探测机器人
  2. 全新型号,戴尔(Dell) EMC PowerEdge R760机架式服务器产品特性及详细技术参数
  3. Gradle安装部署与基础入门详解
  4. 房租大涨?Python6个维度,数万条数据帮你揭穿
  5. 【python学习】-字典学习(访问字典所有键与值、修改与更新字典、删除字典)
  6. 如何从GFP确定最后申请的内存来自哪个zone?
  7. 简单服务发现协议SSDP【转】
  8. 微粒化运营:升级内容产业消费体验(附视频版)
  9. 战地指挥官 服务器维护,战地指挥官有哪些常见问题以及解决方法
  10. 【JAVA】GUI常用组件