博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Linux】剖析僵尸进程和孤儿进程
阅读量:4156 次
发布时间:2019-05-25

本文共 2385 字,大约阅读时间需要 7 分钟。

【Linux】剖析僵尸进程和孤儿进程

  在操作系统内核中,具体的进程状态有:R(运行状态)、S(可中断睡眠状态)、D(磁盘睡眠状态,不可被打断)、T(暂停状态)、t(跟踪状态)、X(死亡状态)、Z(僵尸状态)。那么接下来详细讲解一下僵尸进程(Zombie),它是一个比较特殊的进程状态。


文章目录


一、僵尸进程

  我们先来看一段代码。

#include
#include
int main(){
printf("---begin---\n"); //进程创建 pid_t ret = fork(); if(ret < 0) {
perror("fork error\n"); return 0; } else if(ret == 0) {
//子进程 printf("i am child pid=[%d] ppid[%d]\n",getpid(),getppid()); sleep(20); } else {
//父进程 while(1) {
printf("i am father pid=[%d] ppid[%d]\n",getpid(),getppid()); sleep(1); } } return 0;}

  运行: 可以看到父进程的 PID 是 10377,子进程的 PID 是 10378。

在这里插入图片描述

  分析代码: 通过可以知道,父进程一直在 while 循环,子进程 sleep 个 20 秒会退出。用 ps aux | grep [程序名称] 查看进程信息,可以看到子进程从刚开始的 S(可中断睡眠模式)变成 Z(僵尸状态)。这是为什么呢?

image-20210622215005744


1.1 产生僵尸进程的原因

  子进程先于父进程退出,父进程来不及回收子进程的的资源,导致子进程变成僵尸进程。而此时子进程的 PCB ( task_struct) 还在操作系统内核中被双向链表管理着,但对于子进程而言,程序已经退出,不能执行任何用户写的代码,子进程的状态会变成 Z 状态,刀枪不入。

  僵尸进程对应的进程状态是 Z 状态,并且使用 kill 命令或者 kell -9 都结束不了僵尸进程。

在这里插入图片描述

  补充: 使用 pstack [PID] 命令可以查看程序的调用堆栈情况


1.2 僵尸进程的危害

  如果产生僵尸进程之后,僵尸进程是不能被 kill -9 强杀杀死的 (因为程序已经退出了)。也就意味着操作系统内核用双向链表还管理着僵尸进程的 PCB (task_struct),操作系统内核维护这样的结构体是需要消耗内存的,程序员还结束不了僵尸进程,操作系统就会内存泄漏。


1.3 如何预防僵尸进程的产生

  僵尸进程产生的本质原因是因为子进程先于父进程退出,抓住问题的本质,来看看该如何预防僵尸进程的产生。

  1、让子进程不要先于父进程退出。~呃呃呃 ~ 呃~ 这个好像可能性不大,不可取。

  2、进程等待。~ 呃 ~ 这个可取,优雅的预防。详细内容参考这篇博文👉

  3、将父进程 kill 掉,让僵尸进程成孤儿进程被1号进程所领养,1号进程回收僵尸进程的资源。~ 呃呃 ~ 这个还想不太可取,有点杀敌一千自损八百的感觉。


二、孤儿进程

2.1 产生孤儿进程的原因

  父进程先于子进程退出,子进程会被1号进程所领养(1号进程又被称之为 init 进程)。1号进程会在子进程退出的时候,回收子进程的退出信息,防止子进程变成僵尸进程。


2.2 现象

  我们再来看这段代码。

#include
#include
int main(){
printf("---begin---\n"); //进程创建 pid_t ret = fork(); if(ret < 0) {
perror("fork error\n"); return 0; } else if(ret == 0) {
//子进程 printf("i amchild pid=[%d] ppid[%d]\n",getpid(),getppid()); sleep(20); } else {
//父进程 printf("i am father pid=[%d] ppid[%d]\n",getpid(),getppid()); sleep(5); } return 0;}

  运行: 可以看到父进程的 PID 是 19069,子进程的 PID 是 19070。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYehrNUP-1624418989120)(https://i.loli.net/2021/06/23/mX6U4WyZQvpEBCt.png)]

  分析代码: 通过可以知道,父进程 sleep 个5秒会退出,子进程 sleep 个20 秒然后退出,也就是说父进程先于子进程退出。用 ps -ef | grep [程序名称] 查看进程PID,可以看到 5 秒后父进程退出, 随后子进程的 PPID 从刚开始 19069 变为1,也就是说父进程先于子进程退出,子进程被 1 号进程所领养,1 号进程在子进程退出时回收退出信息。

在这里插入图片描述


2.3 注意

  孤儿进程不是一种进程状态!!!而是一种进程种类的名称。

   一个进程的进程状态只有 R、S、D、T、t、Z、X。


转载地址:http://mnwxi.baihongyu.com/

你可能感兴趣的文章
Flex 布局教程:语法篇
查看>>
年薪50万+的90后程序员都经历了什么?
查看>>
2019年哪些外快收入可达到2万以上?
查看>>
【JavaScript 教程】标准库—Date 对象
查看>>
前阿里手淘前端负责人@winter:前端人如何保持竞争力?
查看>>
【JavaScript 教程】面向对象编程——实例对象与 new 命令
查看>>
我在网易做了6年前端,想给求职者4条建议
查看>>
SQL1015N The database is in an inconsistent state. SQLSTATE=55025
查看>>
RQP-DEF-0177
查看>>
MySQL字段类型的选择与MySQL的查询效率
查看>>
Java的Properties配置文件用法【续】
查看>>
JAVA操作properties文件的代码实例
查看>>
java杂记
查看>>
RunTime.getRuntime().exec()
查看>>
Oracle 分组排序函数
查看>>
VMware Workstation 14中文破解版下载(附密钥)(笔记)
查看>>
日志框架学习
查看>>
日志框架学习2
查看>>
SVN-无法查看log,提示Want to go offline,时间显示1970问题,error主要是 url中 有一层的中文进行了2次encode
查看>>
NGINX
查看>>