以下内容有一部分摘自百度百科,一部分摘自《UNIX环境高级编程》
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸.
怎么查看僵尸进程:
利用命令ps,可以看到有标记为Z的进程就是僵尸进程。
怎样来清除僵尸进程:
1.改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
2.把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
如果一个进程fork一个子进程,但不要等它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止.要实现这个要求,《UNIX环境高级编程》提供了一个十分
巧妙的方法,代码如下
1 #include<sys/types.h> 2 #include<sys/wait.h> 3 #include<fcntl.h> 4 #include<stdio.h> 5 int main() 6 { 7 pid_t pid; 8 if((pid= fork()) <0 ) 9 perror("fork error"); 10 else if(pid==0) 11 { 12 if( (pid=fork())<0 ) 13 perror("fork error"); 14 else if(pid>0) 15 exit(0);/*parent from second fork == first child*/ 16 /*we're the second child;our parent becomes init as soon as 17 our real parent calls exit() in the statement above. 18 Here's where we'd continue executing,knowing that when we're 19 done,init will reap our status. */ 20 sleep(2); 21 printf("second child,parent pid=%d\n",getppid() ); 22 exit(0); 23 } 24 if(waitpid(pid,NULL,0) !=pid)/*wait for first child waitpid函数返回终止子进程的进程ID,第三个参数一般为0 或者是其他选择项*/ 25 perror("waitpid error"); 26 /*we're the parent (the original process); we continue executing. 27 knowing that we're not the parent of the second child.*/ 28 exit(0); 29 }
大家慢慢品味这个程序的巧妙吧,俺道破了就没有什么意思了,你们也会少了很多乐趣
来源:https://www.cnblogs.com/Blue-Moon/archive/2012/10/28/2743858.html