栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

Linux 下孤儿进程与僵尸进程详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux 下孤儿进程与僵尸进程详解

引言:前面的系列文章介绍了进程的基础概念和相关常用的 API,本文将介绍两种比较特殊进程:孤儿进程与僵尸进程,进一步加深对进程的了解,避免进程使用过程中的一些坑点。

文章目录
    • 孤儿进程
    • 僵尸进程
      • 僵尸进程介绍
      • 僵尸进程解决办法
    • 总结

孤儿进程

什么是孤儿进程?

父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就称为孤儿进程(Orphan Process)

每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。 因此孤儿进程并不会有什么危害。

总之:孤儿进程就是父进程退出了,但子进程还在执行。

示例:

#include 
#include 
#include 
#include 

int main()
{
   pid_t pid = -1;
   
   // 创建子进程
   pid = fork();
   if (pid < 0)  // 没有创建成功  
   {   
       perror("fork");
       return 1;
   }
   
   // 父进程
   if (pid > 0)
   {
       printf("父进程休息3秒后退出。。。n");
       printf("父进程: pid:%dn", getpid());
       sleep(1);
       printf("父进程等太累了,现退出了。。。n");
       exit(0);
   }
   
   while (1)
   {
       printf("子进程不停的工作,子进程:pid:%d,父进程:ppid:%dn", getpid(), getppid());
       sleep(1);
   }
   
   return 0;
}

运行结果:

yxm@192:~$ gcc test.c -o test
yxm@192:~$ ./test
父进程休息3秒后退出。。。
父进程: pid:32075
子进程不停的工作,子进程:pid:32076,父进程:ppid:32075
父进程等太累了,现退出了。。。
子进程不停的工作,子进程:pid:32076,父进程:ppid:32075
yxm@192:~$ 子进程不停的工作,子进程:pid:32076,父进程:ppid:1 # 终端可以输入,同时有数据在输出
子进程不停的工作,子进程:pid:32076,父进程:ppid:1
子进程不停的工作,子进程:pid:32076,父进程:ppid:1
  • 一般情况下,运行一个程序时,默认会切换到后台运行,当有输出的时候再切换到前台。

    如上面的运行结果所示:创建子进程后,子进程复制了父进程内核部分的某些数据(比如标准输入、标准输出、标准错误),所以父进程和子进程的标准输出都是当前终端。又因为父进程是前台进程,所以会占用当前终端,但是父进程死亡后,终端占用被解除,但是子进程(变成孤儿进程)没有死亡,其标准输出依旧是当前终端。最终形成了,终端可以输入,同时有数据在输出的特殊情况。

  • 【注意】ubuntu 系统中,字节界面中,产生的孤儿进程会被 1 号( 即 init 进程)进程收养,但是在图形界面中孤儿进程会被非1号进程收养。

僵尸进程 僵尸进程介绍

每个进程结束之后, 都会释放自己地址空间中的用户区数据,内核区的 PCB 没有办法自己释放掉(子进程残留资源(PCB)存放于内核中),需要父进程去释放,进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。

僵尸进程不能被 kill -9 杀死,这样就会导致一个问题,如果父进程不调用 wait() 或 waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。

总之:僵尸进程就是子进程结束了,但父进程没有回收其资源。

#include 
#include 
#include 
#include 

int main()
{
   int i = 0;
   pid_t pid = -1;
   
   // 创建子进程
   pid = fork();
   if (-1 == pid)  // 没有创建成功  
   {   
       perror("fork");
       return 1;
   }
   
   // 子进程
   if (0 == pid)
   {
       for (int i = 0; i < 5; i++)
       {
           printf("子进程做事%dn", i);
           sleep(1);
       }
       printf("子进程想不开,结束了自己。。。。n");
       exit(0);
   }
   else if (pid > 0) 
   {
       while(1) 
       {
           printf("父进程休眠了, pid : %d, ppid : %dn", getpid(), getppid());
           sleep(1);
       }

   }
   return 0;
}
yxm@192:~$ gcc test.c -o test
yxm@192:~$ ./test 
父进程休眠了, pid : 33087, ppid : 30344
子进程做事0
父进程休眠了, pid : 33087, ppid : 30344
子进程做事1
子进程做事2
父进程休眠了, pid : 33087, ppid : 30344
父进程休眠了, pid : 33087, ppid : 30344
子进程做事3
子进程做事4
父进程休眠了, pid : 33087, ppid : 30344
父进程休眠了, pid : 33087, ppid : 30344
子进程想不开,结束了自己。。。。
父进程休眠了, pid : 33087, ppid : 30344
^C
yxm@192:~$ ps -aux
...
...
yxm       33087  0.0  0.0   4516   756 pts/0    S+   00:10   0:00 ./test
yxm       33088  0.0  0.0      0     0 pts/0    Z+   00:10   0:00 [test] #僵尸进程
yxm       33125  0.0  0.0   7476   832 ?        S    00:10   0:00 sleep 180
yxm       33180  0.0  0.1  37860  3420 pts/1    R+   00:10   0:00 ps -aux
僵尸进程解决办法

方式一:僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要,最好在父进程中通过 wait() 和 waitpid() 来避免僵尸进程的产生。

方式二:当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。具体步骤如下:

  1. 首先,需要确定僵尸进程的相关信息,比如父进程 ppid、僵尸进程的 pid 以及命令行等信息。可以执行如下命令:

    ps -e -o stat,ppid,pid,cmd | egrep '^[Zz]'
    

    参数说明:

    • -e:参数用于列出所有的进程;
    • -o:参数用于设定输出格式,这里只输出进程的stat(状态信息)、ppid(父进程pid)、pid(当前进程的pid),cmd(进程的可执行文件);
    • egrep:是linux下的正则表达式工具:
      • ‘^’:这是正则表达式,表示第一个字符的位置
      • [Zz],表示 z 或者大写的 Z 字母,即表示第一个字符为 Z 或者 z 开头的进程数据,因为僵尸进程的状态信息以 Z 或者 z 字母开头。
  2. 然后,可以 kill -9 父进程 pid。kill 之后,僵尸进程将被 init 进程收养并清理

【补充】现在大多数 linux 系统,会将僵尸进程标识为 defunct,所以也可以通过如下命令来获取僵尸进程信息:

ps -ef | grep "defunct"

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:服务器课程

总结

孤儿进程与僵尸进程是两种特殊的进程,一种是父进程先退出,子进程变成孤儿,这种进程没有危害;一种是子进程先退出,父进程没有回收资源导致子进程变成僵尸,会占用系统资源。他们都发生过在父子进程之间。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1032988.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号