1、创建一个僵尸进程
一个例子:
僵尸进程:
源程序:
/*
* zombie.c
* version 1
* Created on: 2013-11-23
* Author: Zhenghua Xue
*/
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>
#include <sys/time.h>
int main (){
intcount = 1;
printf("%dth Spawning;\n",++count);
createChild(count);
return 0;
}
int createChild(int count)
{
pid_t fpid; //fpid表示fork函数返回的值
//int count = 1;
int status = 0;
int duration = 20;
fpid=fork();
if (fpid < 0)
printf("error infork!");
else if (fpid == 0) {
printf("%dst Child PID:%d;\n",count,getpid());
struct timeval start;
struct timeval end;
gettimeofday(&start, NULL);
int t = 0;
while(1){
t++;
t--;
gettimeofday(&end,NULL);
if( (end.tv_sec-start.tv_sec)> duration ) {
printf("child %dexit\n",getpid());
break;
}
//sleep(2);
}
exit(0);//如果不加这行,函数退不出去,大量child sleep后面的PID都变得不固定了
}
else {
printf("%dst ParentPID: %d\n",count,getpid());
//waitpid(-1,&status,WNOHANG);//ifmul waitpid is running when called by main
//不调用waitpid可能会产生僵尸进程
while(1){
sleep(3);
}
}
return 0;
}
2、分析僵尸进程
1)查找僵尸进程
[root@compute-20 oxuezh]# ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
Zl 1 618 [libvirtd] <defunct>
Zl 1 1362 [libvirtd] <defunct>
Zl 1 3039 [libvirtd] <defunct>
Zl 1 12679 [libvirtd] <defunct>
Zl 1 15190 [libvirtd] <defunct>
2)僵尸进程产生的原因:
1)程序运行一段时间,子进程退出,父进程还活着,但父进程未调用waitpid或wait函数,产生了僵尸进程:
2)子进程没有使用exit函数,父进程还活着,即使父进程调用了waitpid或wait函数,依然是僵尸进程。
此时如果杀掉父进程,子进程也就被连带杀掉了:
如果父进程退出后,子进程还在运行,此时,init会立刻接管子进程:如下图所示。
父进程9365退出后:
3)防止产生僵尸进程的方法
1)用wait,waitpid之类的函数获得进程的终止状态,以释放资源。子进程别忘了写exit。如果你能保障你的父进程一定会先于子进程退出,你也可以不用wait或waitpid,子进程结束后,会被过继给init进程,它会回收子进程。
2)waitpid函数是阻塞函数,父进程有可能还需要做其他事情,不愿意阻塞在那。这种情况下,fork两次,其实质还是把孙子进程过继给了init进程,以达到立刻回收目的。可以解决。当然,waitpid函数中加上WNOHANG也可以使得父进程不阻塞,而继续干自己的事。儿子进程产生孙子进程后,马上退出。孙子进程结束后,由于儿子进程已经结束,故会被1号进程init接管,init会释放它。父进程可以干自己想干的事。
3、诡异的僵尸进程
1)父进程为init进程,但就是不收尸
[root@compute-20 oxuezh]# ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
Zl 1 618 [libvirtd] <defunct>
Zl 1 1362 [libvirtd] <defunct>
Zl 1 3039 [libvirtd] <defunct>
Zl 1 12679 [libvirtd] <defunct>
Zl 1 15190 [libvirtd] <defunct>
还未解决,好像除了杀父进程没有更好的办法,但父进程偏偏是1号进程,无法杀。写了一个内核程序,通过改变进程状态试图回收,没有生效,程序可能有问题,继续研究。。。。