先抄录网上一段对僵死进程的描述:



僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait
/ waitpid来取时才释放。 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。



从系统角度来说,处理僵尸进程有两种方法:



1 找到僵死进程的父进程,kill掉父进程,那么僵死进程将变为孤儿进程,孤儿进程在系统中由init进程接管,init进程将回收僵死进程的资源

2 reboot系统,因为僵死进程是不可以被kill掉

如下测试:

[root@limt ~]# ps -ef|grep 21165
root 21165 7459 0 05:51 pts/1 00:00:00 ./a.out
root 21166 21165 0 05:51 pts/1 00:00:00 [a.out] <defunct>
root 21190 8866 0 05:52 pts/3 00:00:00 grep 21165
[root@limt ~]# kill 21165
[root@limt ~]#
[root@limt ~]#
[root@limt ~]# ps -ef|grep 21165 杀掉父进程后,子进程也消失
root 21196 8866 0 05:52 pts/3 00:00:00 grep 21165
[root@limt ~]# ps -ef|grep 16704
root 16704 16703 0 04:06 pts/1 00:00:00 [a.out] <defunct>
root 16719 8866 0 04:06 pts/3 00:00:00 grep 16704
[root@limt ~]#
[root@limt ~]#
[root@limt ~]# kill -9 16704
[root@limt ~]#
[root@limt ~]# ps -ef|grep 16704
root 16704 16703 0 04:06 pts/1 00:00:00 [a.out] <defunct>
root 16725 8866 0 04:06 pts/3 00:00:00 grep 16704
</pre><p></p><p>从开发角度,有两种方法来避免僵死进程:1 通过signal函数处理,因为每一个子进程退出都会向父进程发生一个SIGCHILD信号2 通过fork两次子进程实现,使子进程的父进程为init进程(),大多数守护进程就是这样实现的简单程序演示产生僵死进程的过程:</p><pre code_snippet_id="554626" snippet_file_name="blog_20141217_3_6668512" name="code" class="cpp">一 父进程fork一个子进程然后不使用waitpid函数,直接退出,而子进程sleep 120秒后退出

#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> int main(int argc, char *argv[])
{
pid_t pid; pid = fork();
if (pid == 0) { int iPid = (int)getpid();
fprintf(stderr,"I am child,%d\n",iPid);
sleep(120);
fprintf(stderr, "Child exits\n"); return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"I am parent,%d\n",iPid);
fprintf(stderr, "parent exits\n");
return EXIT_SUCCESS;
} [root@limt ~]# gcc Zom.c
[root@limt ~]# ./a.out [root@limt ~]# ./a.out
I am parent,15019
parent exits
I am child,15020 从输出看父进程先退出,然后子进程运行sleep函数 [root@limt ~]# ps -ef|grep 15019 //查看父进程
root 15046 8866 0 03:29 pts/3 00:00:00 grep 15019
[root@limt ~]#
[root@limt ~]# ps -ef|grep 15020 //查看子进程
root 15020 1 0 03:29 pts/1 00:00:00 ./a.out
root 15056 8866 0 03:29 pts/3 00:00:00 grep 15020 从ps看父进程已经销毁,子进程的父进程号为1,也就是init进程 二 父进程fork一个子进程然后使用waitpid函数,然后退出,而子进程sleep 120秒后退出 #include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> int main(int argc, char *argv[])
{
pid_t pid; pid = fork();
if (pid == 0) { int iPid = (int)getpid();
fprintf(stderr,"I am child,%d\n",iPid);
sleep(120);
fprintf(stderr, "Child exits\n"); return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"I am parent,%d\n",iPid);
waitpid(pid,NULL,0);
fprintf(stderr, "parent exits\n");
return EXIT_SUCCESS;
} [root@limt ~]# gcc Zom.c
[root@limt ~]# ./a.out
I am parent,15187
I am child,15188
Child exits
parent exits 从输出看子进程先退出,父进程一直等待子进程退出后才退出 [root@limt ~]# ps -ef|grep 15187 //查看父进程
root 15187 7459 0 03:32 pts/1 00:00:00 ./a.out
root 15188 15187 0 03:32 pts/1 00:00:00 ./a.out
root 15197 8866 0 03:33 pts/3 00:00:00 grep 15187
[root@limt ~]# ps -ef|grep 15188 //查看子进程
root 15188 15187 0 03:32 pts/1 00:00:00 ./a.out
root 15207 8866 0 03:33 pts/3 00:00:00 grep 15188 三 父进程fork一个子进程,然后使用waitpid函数,最后使用sleep函数,而子进程sleep 40秒后退出
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> int main(int argc, char *argv[])
{
pid_t pid; pid = fork();
if (pid == 0) { int iPid = (int)getpid();
fprintf(stderr,"I am child,%d\n",iPid);
sleep(40);
fprintf(stderr, "Child exits\n"); return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"I am parent,%d\n",iPid);
waitpid(pid,NULL,0);
fprintf(stderr, "sleep....\n");
sleep(120);
fprintf(stderr, "parent exits\n");
return EXIT_SUCCESS;
} [root@limt ~]# ./a.out
I am parent,15673
I am child,15674
Child exits //等待40秒后输出
sleep.... //等待40秒后输出
parent exits 从上面的输出看sleep函数没有立刻执行,而是等待子进程运行完成才执行,实际是在等待waitpid函数返回 [root@limt ~]# ps -ef|grep 15673 //程序运行40秒内
root 15673 7459 0 03:43 pts/1 00:00:00 ./a.out
root 15674 15673 0 03:43 pts/1 00:00:00 ./a.out
root 15681 8866 0 03:44 pts/3 00:00:00 grep 15673
[root@limt ~]# ps -ef|grep 15674 //程序运行40秒内
root 15674 15673 0 03:43 pts/1 00:00:00 ./a.out
root 15692 8866 0 03:44 pts/3 00:00:00 grep 15674
[root@limt ~]#
[root@limt ~]# ps -ef|grep 15673 //程序运行40秒外
root 15673 7459 0 03:43 pts/1 00:00:00 ./a.out
root 15725 8866 0 03:44 pts/3 00:00:00 grep 15673
[root@limt ~]# ps -ef|grep 15674 //程序运行40秒外,子进程已经销毁
root 15727 8866 0 03:44 pts/3 00:00:00 grep 15674
[root@limt ~]#
[root@limt ~]# ps -ef|grep 15673 //程序运行120秒外
root 15798 8866 0 03:46 pts/3 00:00:00 grep 15673 四 父进程fork一个子进程,不使用waitpid函数然,而是sleep 120秒,而子进程sleep 1秒后退出 #include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> int main(int argc, char *argv[])
{
pid_t pid; pid = fork();
if (pid == 0) { int iPid = (int)getpid();
fprintf(stderr,"I am child,%d\n",iPid);
sleep(1);
fprintf(stderr, "Child exits\n"); return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"I am parent,%d\n",iPid);
fprintf(stderr, "sleep....\n");
sleep(120);
fprintf(stderr, "parent exits\n");
return EXIT_SUCCESS;
} [root@limt ~]# ./a.out
I am parent,16026
sleep....
I am child,16027
Child exits
parent exits 从上面输出看子进程先于父进程退出 [root@limt ~]# ps -ef|grep 16026 //查看父进程
root 16026 7459 0 03:51 pts/1 00:00:00 ./a.out
root 16027 16026 0 03:51 pts/1 00:00:00 [a.out] <defunct>
root 16039 8866 0 03:51 pts/3 00:00:00 grep 16026
[root@limt ~]#
[root@limt ~]# ps -ef|grep 16027 //查看子进程,子进程处于僵死状态
root 16027 16026 0 03:51 pts/1 00:00:00 [a.out] <defunct>
root 16046 8866 0 03:51 pts/3 00:00:00 grep 16027 [root@limt ~]# top //top 进程显示存在一个僵死进程 top - 04:02:20 up 2:46, 4 users, load average: 0.21, 0.15, 0.15
Tasks: 280 total, 1 running, 278 sleeping, 0 stopped, 1 zombie
Cpu(s): 1.2%us, 0.6%sy, 0.0%ni, 97.4%id, 0.7%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 2050752k total, 1819480k used, 231272k free, 141876k buffers
Swap: 6291448k total, 0k used, 6291448k free, 775368k cached [root@limt ~]# ps -ef|grep 16027 //120秒后僵死进程消失
root 16513 8866 0 04:01 pts/3 00:00:00 grep 16027

C程序演示产生僵死进程的过程的更多相关文章

  1. 【Linux】进程的结构,创建,结束,以及程序转化为的进程的过程

    本文内容: 1.进程的结构 2.程序转化为进程的过程 3.进程的创建 4.进程的结束 背景知识: 1.进程是计算机中处于运行的程序的实体 2.进程是线程的容器 3.程序本身只是指令,数据以及组织形式的 ...

  2. Android应用程序进程启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...

  3. Android应用程序进程启动过程(后篇)

    前言 在前篇中我们讲到了Android应用程序进程启动过程,这一篇我们来讲遗留的知识点:在应用程序进程创建过程中会启动Binder线程池以及在应用程序进程启动后会创建消息循环. 1.Binder线程池 ...

  4. Android应用程序进程启动过程(前篇)

    在此前我讲过Android系统的启动流程,系统启动后,我们就比较关心应用程序是如何启动的,这一篇我们来一起学习Android7.0 应用程序进程启动过程,需要注意的是“应用程序进程启动过程”,而不是应 ...

  5. 【UNIX网络编程(三)】TCP客户/server程序演示样例

    上一节给出了TCP网络编程的函数.这一节使用那些基本函数编写一个完毕的TCP客户/server程序演示样例. 该样例运行的过程例如以下: 1.客户从标准输入读入一行文本,并写给server. 2.se ...

  6. C/C++程序从编译到链接的过程

    编译器是一个神奇的东西,它能够将我们所编写的高级语言源代码翻译成机器可识别的语言(二进制代码),并让程序按照我们的意图按步执行.那么,从编写源文件代码到可执行文件,到底分为几步呢?这个过程可以总结为以 ...

  7. linux内核学习之六 进程创建过程学习

    一 关于linux进程概念的补充 关于进程的基本概念这里不多说,把自己的学习所得作一些补充: 1. 在linux内核中,系统最多可以有64个进程同时存在. 2.linux进程包含的关键要素:一段可执行 ...

  8. 【转载】详解CreateProcess调用内核创建进程的过程

    原文:详解CreateProcess调用内核创建进程的过程 昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是, 为了以防万一,也为了深入学 ...

  9. 是什么在.NET程序关闭时阻碍进程的退出?

    在平时使用软件或是.NET程序开发的过程中,我们有时会遇到程序关闭后但进程却没有退出的情况,这往往预示着代码中有问题存在,不能正确的在程序退出时停止代码执行和销毁资源.这个现象有时并不容易被察觉,但在 ...

随机推荐

  1. Pyqt QComboBox 省市区县联动效果

    在Qt中, QComboBox方法窗口组件允许用户从列表清单中选择,在web中就是select标签,下拉选项. 省市区县的联动就是currentIndexChanged 获取当前的Index,通过这个 ...

  2. protobuf-net 对象二进制序列化与反序列号(转)

    概述: Protobuf是google开源的一个项目,用户数据序列化反序列化,google声称google的数据通信都是用该序列化方法.它比xml格式要少的多,甚至比二进制数据格式也小的多. Prot ...

  3. 【PHP自定义显示系统级别的致命错误和用户级别的错误】

    使用方法set_error_handler可以自定义用户级别的错误和系统级别的错误信息显示和处理 用户级别的错误使用trigger_error方法产生一个用户级别的错误信息 代码示例: 系统级别的错误 ...

  4. hdu 4763 kmp ***

    找AEAEA形式的字符串最长的A长度,E可以为空 只可意会,不可言传,懂kmp即可 #include <stdio.h> #include <string.h> #includ ...

  5. 深入理解ASP.NET 5的依赖注入

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ASP.NET 5整个底层都架构于依赖注入机制之下,今天介绍的文章详细介绍了内置依赖注 ...

  6. 求数组的长度 C

    对于数组array,计算其占用内存大小和元素个数的方法如下: C/C++ code ? 1 2 3 4 5 //计算占用内存大小 sizeof(array)   //计算数组元素个数 sizeof(a ...

  7. SQLServer 维护脚本分享(10)索引

    --可添加索引的字段 migs.user_seeks,migs.avg_total_user_cost,migs.avg_user_impact,migs.last_user_seek ,mid.st ...

  8. nginx配置文件nginx.conf

    #定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数.worker_processes 8; #全局错误日志定义类型,[ debug | in ...

  9. HDU 3461 Code Lock(并查集)

    很好的一个题,思想特别6 题意:给你小写字母个数n,每个字母可以向上翻动,例如:d->c,a->z.然后给你m对数(L,R)(L<=R),表示[L,R]之间可以同时向上翻动,且翻动后 ...

  10. NDK各版本下载

    含r8e,r9d,r10c 其中x86_64代表64位系统 官网上只有最新版下载链接,如果想要下载以前的版本,可打开 https://archive.org/web/ 然后输入 http://deve ...