linux: 僵尸进程

xiaoxiao2021-02-28  71

上一篇文章( http://blog.csdn.net/qingsong3333/article/details/77756042)讲了如何使用fork()函数产生一个的子进程,如果控制不好子进程与父进程的关系,则可能产生僵尸进程

1. 如果父进程先于子进程结束,那么子进程的PPID就会变为1,直到子进程结束,子进程的状态正常。下面的例子中,子进程运行15s,父进程运行3s:

qingsong@db2a:~/linuxc$ cat zombie1.c /* filename zombie1.c */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main() { pid_t pid; pid=fork(); if (pid < 0) printf("Fork error\n"); else if (pid == 0) { sleep(15); printf("I'm child and I'm end\n"); } else { system("ps -al"); sleep(3); printf("I'm parent and I'm end\n"); } return 0; } qingsong@db2a:~/linuxc$ gcc -o zombie1 zombie1.c qingsong@db2a:~/linuxc$ ./zombie1 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44131 58189 0 90 10 - 1053 wait pts/0 00:00:00 zombie1 1 S 1000 44132 44131 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie1 0 S 1000 44133 44131 0 90 10 - 1116 wait pts/0 00:00:00 sh 0 R 1000 44134 44133 0 90 10 - 2502 - pts/0 00:00:00 ps I'm parent and I'm end qingsong@db2a:~/linuxc$ I'm child and I'm end qingsong@db2a:~/linuxc$

另外一个shell里观察到的: 1. 父进程结束之前:

qingsong@db2a:~$ ps -al F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44131 58189 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie1 1 S 1000 44132 44131 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie1 0 R 1000 44135 39666 0 80 0 - 2502 - pts/2 00:00:00 ps 2. 父进程结束之后,子进程结束之前,可以看到,父进程没了,子进程的PPID变为1

qingsong@db2a:~$ ps -al F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 1 S 1000 44132 1 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie1 0 R 1000 44156 39666 0 80 0 - 2502 - pts/2 00:00:00 ps 2. 如果子进程先结束呢?它就会变成僵尸进程,下面的例子中,子进程运行3s,父进程运行15s:

qingsong@db2a:~/linuxc$ cat zombie2.c /* filename zombie1.c */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main() { pid_t pid; pid=fork(); if (pid < 0) printf("Fork error\n"); else if (pid == 0) { sleep(3); printf("I'm child and I'm end\n"); } else { system("ps -al"); sleep(15); printf("I'm parent and I'm end\n"); } return 0; } qingsong@db2a:~/linuxc$ gcc -o zombie2 zombie2.c qingsong@db2a:~/linuxc$ ./zombie2 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44560 58189 0 90 10 - 1053 wait pts/0 00:00:00 zombie2 1 S 1000 44561 44560 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie2 0 S 1000 44562 44560 0 90 10 - 1116 wait pts/0 00:00:00 sh 0 R 1000 44563 44562 0 90 10 - 2502 - pts/0 00:00:00 ps I'm child and I'm end I'm parent and I'm end qingsong@db2a:~/linuxc$ F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44560 58189 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie2 1 Z 1000 44561 44560 0 90 10 - 0 - pts/0 00:00:00 zombie2 <defunct> 0 R 1000 44585 39666 0 80 0 - 2502 - pts/2 00:00:00 ps

在另一个shell里看到的: 1. 子进程结束之前:

qingsong@db2a:~$ ps -al F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44560 58189 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie2 1 S 1000 44561 44560 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie2 0 R 1000 44566 39666 0 80 0 - 2502 - pts/2 00:00:00 ps 2. 子进程结束之后,可以看到子进程变成了僵尸进程,S列为Z,最后也标注了defunct:

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 44560 58189 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie2 1 Z 1000 44561 44560 0 90 10 - 0 - pts/0 00:00:00 zombie2 <defunct> 0 R 1000 44585 39666 0 80 0 - 2502 - pts/2 00:00:00 ps 子进程变为僵尸进程的原因如下:

一个僵尸进程产生的过程是:父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。

http://www.cnblogs.com/hazir/p/zombie_process.html

也就是说,只要子进程先运行完了,它就会变为僵尸进程,需要父进程使用wait函数来“清理”。所以,僵尸进程是正常现象!但父进程一直不清理,才是异常的!

3. 再进一步,如果子进程在正常状态(非僵尸态)下,父进程就被杀掉了呢

下面这个程序和zombi1是一样的,不过为了有时间手动杀掉父进程,把sleep的时间扩大了 Sesion A:

qingsong@db2a:~/linuxc$ cat zombie3.c /* filename zombie3.c */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main() { pid_t pid; pid=fork(); if (pid < 0) printf("Fork error\n"); else if (pid == 0) { sleep(30); printf("I'm child and I'm end\n"); } else { system("ps -al"); sleep(15); printf("I'm parent and I'm end\n"); } return 0; } qingsong@db2a:~/linuxc$ gcc -o zombie3 zombie3.c qingsong@db2a:~/linuxc$ ./zombie3 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 45545 58189 0 90 10 - 1053 wait pts/0 00:00:00 zombie3 1 S 1000 45546 45545 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie3 0 S 1000 45547 45545 0 90 10 - 1116 wait pts/0 00:00:00 sh 0 R 1000 45548 45547 0 90 10 - 2502 - pts/0 00:00:00 ps Killed <--Session B里将父进程杀掉 qingsong@db2a:~/linuxc$ I'm child and I'm end qingsong@db2a:~/linuxc$

Session B:里可以看到,杀掉父进程之后,子进程的PPID自动变为1,即由init接管,且状态正常

qingsong@db2a:~$ ps -al F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 S 1000 45545 58189 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie3 1 S 1000 45546 45545 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie3 0 R 1000 45549 39666 0 80 0 - 2502 - pts/2 00:00:00 ps qingsong@db2a:~$ kill -9 45545 <--杀掉父进程 qingsong@db2a:~$ ps -al F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 1 S 1000 45546 1 0 90 10 - 1053 hrtime pts/0 00:00:00 zombie3 <--PPID变为1 0 R 1000 45566 39666 0 80 0 - 2502 - pts/2 00:00:00 ps qingsong@db2a:~$ ps -al <--等30s,即子进程结束之后 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 2876 58189 0 80 0 - 1054 signal pts/0 00:00:00 1.9.1 0 R 1000 45745 39666 0 80 0 - 2502 - pts/2 00:00:00 ps 4. 如果子进程在僵尸状态下,父进程被杀掉了呢? 那么子进程就会由init接管,PPID变为1。这个僵尸进程保留在进程表中直到被init进程发现并释放。进程表越大,过程就越慢。所以要尽量避免僵尸进程。

转载请注明原文地址: https://www.6miu.com/read-59942.html

最新回复(0)