linux父子进程问题——孤儿进程与僵尸进程[总结]

2023-05-16

今天遇到一个linux进程启动时指定Max open files不对的问题,导致程序建立socket异常,进而导致fullgc问题,影响正常服务。所以顺带又温习了下linux下的父子进程的特性。

孤儿进程与僵尸进程[总结]https://www.cnblogs.com/Anker/p/3271773.html

1、前言

  之前在看《unix环境高级编程》第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊。今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧。晚上回来google了一下,再次参考APUE,认真总结一下,加深理解。

2、基本概念

  我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

  孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

3、问题及危害

  unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等

但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。

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

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

  任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。  如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

  僵尸进程危害场景:

  例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样这些已经僵死的孤儿进程 就能瞑目而去了。

3、孤儿进程和僵尸进程测试

孤儿进程测试程序如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
 
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;
 }

测试结果如下:

僵尸进程测试程序如下所示:


 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <errno.h>
 4 #include <stdlib.h>
 5 
 6 int main()
 7 {
 8     pid_t pid;
 9     pid = fork();
10     if (pid < 0)
11     {
12         perror("fork error:");
13         exit(1);
14     }
15     else if (pid == 0)
16     {
17         printf("I am child process.I am exiting.\n");
18         exit(0);
19     }
20     printf("I am father process.I will sleep two seconds\n");
21     //等待子进程先退出
22     sleep(2);
23     //输出进程信息
24     system("ps -o pid,ppid,state,tty,command");
25     printf("father process is exiting.\n");
26     return 0;
27 }  

测试结果如下所示:

僵尸进程测试2:父进程循环创建子进程,子进程退出,造成多个僵尸进程,程序如下所示:


 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <errno.h>
 5 
 6 int main()
 7 {
 8     pid_t  pid;
 9     //循环创建子进程
10     while(1)
11     {
12         pid = fork();
13         if (pid < 0)
14         {
15             perror("fork error:");
16             exit(1);
17         }
18         else if (pid == 0)
19         {
20             printf("I am a child process.\nI am exiting.\n");
21             //子进程退出,成为僵尸进程
22             exit(0);
23         }
24         else
25         {
26             //父进程休眠20s继续创建子进程
27             sleep(20);
28             continue;
29         }
30     }
31     return 0;
32 }  

程序测试结果如下所示:

4、僵尸进程解决办法

(1)通过信号机制

  子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:


 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <errno.h>
 4 #include <stdlib.h>
 5 #include <signal.h>
 6 
 7 static void sig_child(int signo);
 8 
 9 int main()
10 {
11     pid_t pid;
12     //创建捕捉子进程退出信号
13     signal(SIGCHLD,sig_child);
14     pid = fork();
15     if (pid < 0)
16     {
17         perror("fork error:");
18         exit(1);
19     }
20     else if (pid == 0)
21     {
22         printf("I am child process,pid id %d.I am exiting.\n",getpid());
23         exit(0);
24     }
25     printf("I am father process.I will sleep two seconds\n");
26     //等待子进程先退出
27     sleep(2);
28     //输出进程信息
29     system("ps -o pid,ppid,state,tty,command");
30     printf("father process is exiting.\n");
31     return 0;
32 }
33 
34 static void sig_child(int signo)
35 {
36      pid_t        pid;
37      int        stat;
38      //处理僵尸进程
39      while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
40             printf("child %d terminated.\n", pid);
41 }  

测试结果如下所示:

(2)fork两次
  《Unix 环境高级编程》8.6节说的非常详细。原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。测试程序如下所示:


 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <errno.h>
 5 
 6 int main()
 7 {
 8     pid_t  pid;
 9     //创建第一个子进程
10     pid = fork();
11     if (pid < 0)
12     {
13         perror("fork error:");
14         exit(1);
15     }
16     //第一个子进程
17     else if (pid == 0)
18     {
19         //子进程再创建子进程
20         printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());
21         pid = fork();
22         if (pid < 0)
23         {
24             perror("fork error:");
25             exit(1);
26         }
27         //第一个子进程退出
28         else if (pid >0)
29         {
30             printf("first procee is exited.\n");
31             exit(0);
32         }
33         //第二个子进程
34         //睡眠3s保证第一个子进程退出,这样第二个子进程的父亲就是init进程里
35         sleep(3);
36         printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());
37         exit(0);
38     }
39     //父进程处理第一个子进程退出
40     if (waitpid(pid, NULL, 0) != pid)
41     {
42         perror("waitepid error:");
43         exit(1);
44     }
45     exit(0);
46     return 0;
47 }  

测试结果如下图所示:

5、参考资料

《unix环境高级编程》第八章

僵死进程与孤儿进程_罗索

僵尸进程和孤儿进程-oniziga-ChinaUnix博客

点点-互联网大数据服务商

孤儿进程和僵尸进程_青青的专栏--C/C++ OOA/D Design Pattern-CSDN博客_孤儿进程

区别之守护进程 孤儿进程 僵尸进程_yuwenliang的专栏-CSDN博客_孤儿进程

linux父子进程问题 - 鲁仕林 - 博客园

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

linux父子进程问题——孤儿进程与僵尸进程[总结] 的相关文章

  • 关于如何去寻找自己的另一半和我的爱情观

    用这个题目 xff0c 我自己都没想到 xff0c 因为目前我还是单身 xff0c 虽然谈过几次恋爱 xff0c 但最后都成了白月光 下面我给出了自己的反思 xff0c 也找了我的领导谈心 xff0c 也看了一些书 xff0c 想找到为什么
  • 一篇文章完全讲解C语言指针

    指针对于C来说太重要 然而 xff0c 想要全面理解指针 xff0c 除了要对C语言有熟练的掌握外 xff0c 还要有计算机硬件以及操作系统等方方面面的基本知识 所以本文尽可能的通过一篇文章完全讲解指针 为什么需要指针 xff1f 指针解决
  • MySQL定时备份

    MySQL定时备份实例 xff1a 每周一晚上3 00 xff0c 备份数据库服务器上webdb库的所有数据到系统的 mysqlbak目录中 xff0c 使用系统日期做备份文件名 xff01 span class token operato
  • 一篇文章完全讲解C语言指针

    https mp weixin qq com s biz 61 MzU3NDU5NDczMw 61 61 amp mid 61 2247504309 amp idx 61 5 amp sn 61 5421ee86fb1be92b43d99f
  • 读懂Adaptive Autosar架构-基础应用篇

    对于Adaptive AUTOSAR xff0c 咱们经常会看到这句话 xff1a Write once Adopt everywhere 但实际上理想很丰满 xff0c 现实很骨感 毕竟Classic Platform xff08 后面简
  • 软件架构的定义

    一 软件架构的定义 我们先讨论一下什么是软件架构 xff1f 对于软件架构并没有一个标准的定义 xff0c 但是你和软件工程师谈到架构的时候 xff0c 他们会知道这些都会是架构的内容 是不是要分层 xff0c 如何处理事件 xff0c 如
  • 一文了解V2X技术栈及其产业链

    C V2X会给未来出行交通带来怎样的改变 xff1f 会在哪些场景下发挥作用 xff1f 这条产业链里面的公司又是哪些 xff1f 大厂们在V2X上的投入又是如何呢 xff1f 本文可以给你一个答案 1 为什么需要V2X 随着C V2X及5
  • 精力管理分享

    你是否长时间工作却没有时间休息 是否总是感到压力很大 xff0c 时间不够用 xff1f 是否经常觉得很疲惫 xff0c 怎么调整都找不到状态 xff1f 然而 xff0c 不论是工作还是生活 xff0c 我们每个人都需要进行自我能量的调节
  • 目标管理

    业务能力很突出 xff0c 管理能力跟不上 xff0c 怎么办 xff1f 这节课帮你补全管理必修模块 xff0c 掌握全面的管理视角 学了很多管理手段 xff0c 总是用不上怎么办 xff1f 用工具统一管理语言 xff0c 拿来就能用
  • 深入浅出理解SOME/IP

    详解SOME IP协议文档 1 知乎 知乎 xff0c 中文互联网高质量的问答社区和创作者聚集的原创内容平台 xff0c 于 2011 年 1 月正式上线 xff0c 以 让人们更好地分享知识 经验和见解 xff0c 找到自己的解答 为品牌
  • SOME/IP-SD 深入浅出

    文章中 xff0c 我们了解了一条完整的SOME IP报文应该长什么样子 xff0c 但这显然是不够的 xff0c 至少还有以下这几个问题并没有得到明确的解决 xff1a Client如何发现服务 当服务不可用时 xff0c 如何通知Cli
  • Segmentation Fault错误原因总结

    一 什么是 Segmentation fault in Linux 所谓的段错误就是指访问的内存超过了系统所给这个程序的内存空间 xff0c 通常这个值是由gdtr来保存的 xff0c 他是一个48位的寄存器 xff0c 其中的32位是保存
  • 漫谈QNX(架构/进程,线程,同步,进程间通信IPC)

    1 架构 说起Blackberry的QNX操作系统 想必大家都听说过 xff0c 但到底为什么QNX能如此有名 xff1f 难道微软的Windows和Linux都不能与之抗衡 xff1f 美国NASA的太空接驳飞船也使用QNX操作系统 QN
  • Linux系统安装后需要做什么?

    安装完linux系统之后需要做的事情 以centos7为例 xff1a 1 用root用户登录 2 tab键补全安装包 yum span class token operator span y install bash span class
  • ETAS Adaptive AUTOSAR 自适应平台示例视频教程

    ETAS AP AUTOSAR自适应平台示例视频教程 本系列文章旨在提供一个详细的操作指南 xff0c 以构建ETAS AP AUTOSAR自适应平台的示例 实践练习的目标是加强AUTOSAR自适应平台中的理论概念 xff0c 并更好地理解
  • 什么是微内核,看这一篇就够了

    微内核是将服务转移到进程上的一种内核模式 宏内核是一种传统的内核结构 xff0c 它将进程管理 xff0c 内存管理等各项服务功能都放到内核中去 xff0c 通常用在通用式的内核上 xff0c 如unix xff0c linux等 两个系统
  • AUTOSAR的E2E通信安全

    AUTOSAR标准的安全通信为支持功能安全 xff0c AUTOSAR标准结合ISO 26262功能安全标准 xff0c 在基础软件层从安全执行 安全通信以及安全内建测试三个方面做出了规范 xff0c 并规范 AUTOSAR标准的安全通信
  • bridged networking(桥接模式)和network address translation(NAT模式)

    在NAT模式下 xff1a 王五的主机里面的虚拟机有一个虚拟的网卡有一个IP地址192 168 100 88 xff0c 可以在内部生成一个虚拟的地址192 168 100 xff19 xff19 与之通信 xff0c 然后通过代理利用主机
  • Linux 目录结构

  • Adaptive AUTOSAR 简介 (2021版)

    目录 1 Adaptive AUTOSAR 简介 Adaptive平台 一种新的 AUTOSAR 1 1 Adaptive的案例 1 2 经典平台与适应性平台的比较 1 3 单一系统 1 4 架构 逻辑架构 1 5 软件架构 本文图片来源

随机推荐

  • 从Adaptive AUTOSAR的角度看SOA

    前言 身处汽车行业的我们深知 xff0c 新技术的应用或者新概念的提出 xff0c 一定是事出有因的 通常是为了抢夺新技术高地 xff0c 让汽车更好地满足未来的需求 那么 xff0c 汽车电子电气架构领域掀起的这股SOA热潮是由什么导致的
  • 什么是BSP?理解LINUX BSP

    BSP 可支持操作系统更好地运行于硬件主板 BSP xff08 Board Support Package xff09 指板级支持包 对于一般的嵌入式系统 xff0c 硬件部分需要嵌入式硬件工程师设计硬件电路 xff0c 而新出厂的电路板需
  • c++11 std::move() 的使用

    std move函数可以以非常简单的方式将左值引用转换为右值引用 xff08 左值 左值引用 右值 右值引用 参见 xff1a http www cnblogs com SZxiaochun p 8017475 html xff09 通过s
  • Adaptive AUTOSAR 学习笔记 3 - AP 背景、技术及特征

    本系列学习笔记基于 AUTOSAR Adaptive Platform 官方文档 R20 11 版本 本文从AUTOSAR EXP PlatformDesign pdf开始 xff0c 一边学习 xff0c 一边顺带着翻译一下 尽力而为 x
  • MySQL导入数据(命令行、脚本方式)

    docker安装MySQL并导入数据 安装步骤省略 xff0c 详细可参考百度上文档 一 命令方式 1 把数据传进服务器中 dfc span class token annotation punctuation 64 BBC span sp
  • Linux 终端快捷键

    Linux 终端快捷键 你可能会有这样的疑问 xff1a 对于有些快捷键 xff0c 明明有等效的 一个按键就能搞定的操作 xff0c 为什么非要舍近求远 用两个组合键来实现 xff1f 当对键盘 终端命令熟练到一定程度之后 xff0c 你
  • Adaptive AUTOSAR----Adaptive studio

    Adaptive studio Adaptive Studio 是包含在 RTA VRTE SK 中的 AUTOSAR 编辑器 Adaptive studio 通过高级抽象支持所有 adaptives autosar arxml 元素的配置
  • Linux tcpdump命令详解

    简介 用简单的话来定义tcpdump xff0c 就是 xff1a dump the traffic on a network xff0c 根据使用者的定义对网络上的数据包进行截获的包分析工具 tcpdump可以将网络中传送的数据包的 头
  • 什么是 E2E 保护 ?

    安全在每个领域都是一个永恒的话题 xff0c 汽车也不例外 xff0c 而随着最近几年汽车电动化 智能化和网联化的发展 xff0c 汽车安全也越来越受到用户及开发人员的重视 xff0c 安全的要素也是多方面的 xff0c 例如用户可能关心在
  • CAN总线基础

    概述 汽车电子设备的不断增多 xff0c 对汽车上的线束分布以及信息共享与交流提出了更高的要求 传统的电气系统往往采用单一连接的方式通信 xff0c 这必将带来线束的冗余以及维修的成本的提高 单一布线连接 传统的单一通信的对接方式 xff0
  • 说一说LIN总线

    前几天小编画点时间看了一些关于LIN总线基础的内容 xff0c 把其中的关键点提取了出来 xff0c 在这里分享给大家 在这里你可能要问 不都有CAN总线了吗 xff1f 这个LIN总线又是从哪里来的 xff1f 其实理由很简单 xff0c
  • CAN FD 介绍

    随着电动汽车 xff0c 无人驾驶汽车技术的快速发展 xff0c 以及对汽车高级驾驶辅助系统和人机交互HMI需求的增加 xff0c 传统的CAN总线在传输速率和带宽等方面越来越显得力不从心 xff0c 其主要原因如下 xff1a 1 通常整
  • FlexRay 介绍

    汽车上的总线技术包括 xff1a LIN CAN CAN FD FlexRay MOST及Ethernet xff0c 我们之前已经分享了LIN xff0c CAN CAN FD总线 在开始阅读之前 xff0c 如果你对已介绍的总线技术还不
  • FlexRay总线原理及应用

    由于传统的CAN解决方案不能满足汽车线控系统 xff08 X by Wire xff09 的要求 于是在 2000 年 9 月 xff0c 宝马和戴姆勒克莱斯勒联合飞利浦和摩托罗拉成立了 FlexRay 联盟 该联盟致力于推广 FlexRa
  • SENT信号介绍

    Vehicle攻城狮 The people who are crazy enough to think they can change the world are the ones who do SENT背景介绍 提到车载总线 xff0c
  • Linux 日志管理

    常用日志文件 系统日志是由一个名为syslog的服务管理的 xff0c 如以下日志文件都是由syslog日志服务驱动的 xff1a var log boot log xff1a 录了系统在引导过程中发生的事件 xff0c 就是Linux系统
  • SPI 通讯协议

    Cuitbasics 汽车ECU设计 2 2 当您将微控制器连接到传感器 xff0c 显示器或其他模块时 xff0c 您是否考虑过这两种设备是如何相互通信的 xff1f 他们到底在说什么 xff1f 事实上电子设备之间的通信就像人类之间的交
  • UART串口通讯

    UART代表通用异步接收器 发送器也称为串口通讯 xff0c 它不像SPI和I2C这样的通信协议 xff0c 而是微控制器中的物理电路或独立的IC UART的主要目的是发送和接收串行数据 xff0c 其最好的优点是它仅使用两条线在设备之间传
  • 一文搞懂AUTOSAR的DEM模块

    Dem全称为Diagnostic Event Manager xff0c 负责故障事件的处理 故障数据的存储和管理 简单说其功能是故障事件确认前的故障debounce xff0c 故障事件确认时的故障数据存储 xff0c 故障发生后的故障老
  • linux父子进程问题——孤儿进程与僵尸进程[总结]

    今天遇到一个linux进程启动时指定Max open files不对的问题 xff0c 导致程序建立socket异常 xff0c 进而导致fullgc问题 xff0c 影响正常服务 所以顺带又温习了下linux下的父子进程的特性 孤儿进程与