Linux 僵死进程(zombie)
Posted by jiayi | Posted in APUE | Posted on 26-10-2008
3
Linux 中有一种“死不瞑目”的进程,叫僵死进程(zombie)。一句话定义僵死进程:In UNIX System terminology, a process that has terminated, but whose parent has not yet waited for it, is called a zombie. 这些进程可以通过 ps 命令查看:ps -el ,带有 Z 标记的为僵死进程。也可以 ps -ef | grep defunc
一个进程exit()后,内核会将它的exit status 转换为 termination status,并由内核记录。可见这个结束的进程并没有真正的被销毁,虽然它已经不占用任何内存和cpu资源,没有任何可执行代码,也不能被调度,但却残留在进程列表里,一旦这种进程过多,系统性能肯定受其影响。这就需要它的父进程为它“收尸”,来获取已经terminate的子进程的终止状态(通常由wait() 和waitpid() 来完成)。如果父进程在子进程之前退出,子进程会变成僵死进程了么…?不会的,这些子进程会被1号进程init 收留,并由1号进程init为它们”收尸“。
为了更好的说明僵死进程这个东东,我们人为的制造一个。。。
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/stat.h>
#include <sys/wait.h>
int
main(void)
{
pid_t pid;
pid_t pid1;
pid_t wait_pid;
printf("The parent’s pid is %dn",getpid());
if ((pid = fork()) < 0)
{
perror("fork error");
}
else if (pid == 0)
{ /* first child */
if ((pid = fork()) < 0)
perror("fork error");
else if (pid > 0)
{
printf("First child of the parent is %dn",getpid());
exit(0);
}
sleep(1);
printf("First child’s child awaked…n");
printf("pid = %d, parent pid = %dn",getpid(), getppid());
exit(0);
}
else /*The parent process*/
{
if((pid1=fork())<0)
perror("Fork");
else if(pid1==0)
{
printf("Second child of the parent is %dn",getpid());
exit(0);
}
}
sleep(3);
printf("parent awaked…n");
if ((wait_pid=waitpid(pid1, NULL, 0)) == pid1) // wait for second child
{
printf("seconde child has been waited: value of wait_pid is %dn",wait_pid);
}
while(1)
;
exit(0);
}
编译运行得到
jiayi:/home/jiayi/apue # ./waitpid
The parent’s pid is 20334
Second child of the parent is 20337
First child of the parent is 20335
First child’s child awaked…
pid = 20336, parent pid = 1
parent awaked…
seconde child has been waited: value of wait_pid is 20337
另一个终端运行 ps -ef 得到最后三行
root 20334 9667 90 21:55 pts/7 00:37:28 ./waitpid
root 20335 20334 0 21:55 pts/7 00:00:00 [waitpid] <defunct>
jiayi 20459 20152 0 22:37 pts/2 00:00:00 ps -ef
一句一句分析程序打印的结果
此程序的进程号为20334;父进程第二个子进程的进程号为20337;父进程第一个子进程的进程号为20335(从这两个进程的打印顺序可以看出,两个进程存在竞争);20335的子进程 20336在睡觉,醒来后发现它的父进程变成了1,这是因为20335 在 20336结束之前已经结束,20336进程被1号init收留;父进程在睡觉,醒来后通过waitpid()成功获取第二个子进程20337的终止信息,然后很没素质的作起了无限循环…
至此,父进程在循环,两个子进程以及第一个子进程的子进程都已终止。其中第二个子进程 20337 被收尸,彻底销毁;子进程的子进程被1号init 收尸,也完全销毁;第一个子进程呢…? 看一下 ps 命令的结果,同样一句一句看:
20334号父进程在运行,因为它在作无限循环…;20335号子进程由defunct 标记,说明是一个僵死进程…… 另外两个子进程没有被发现,因为它们已经彻底解脱…
实验还没有结束,这时我们摁下 ctrl + c 将无限循环的父进程 20334 干掉,重新 ps -ef ,那个僵死进程也不见了。。。这是因为父进程 20334 被干掉后,僵死进程被1号init ”收尸“,从而彻底解脱。。。
额,弄一个僵死进程出来还挺不容易的。。。

