什么是僵尸进程?
当一个子进程终止时,操作系统会保留该进程的一些信息(如进程ID、退出状态等),直到父进程读取这些信息。这段时间内,该子进程处于一个特殊的状态,称为僵尸进程(Zombie Process)。
僵尸进程的特征:
- 进程已经终止,但仍在进程表中占有一个条目。
- 它的资源(如内存)已被释放,但进程控制块(PCB)等信息仍然保留。
- 等待父进程调用wait()或waitpid()来获取它的终止状态。
为什么要避免僵尸进程?
如果不及时回收僵尸进程,它们会在系统的进程表中占据条目。虽然每个僵尸进程占用的资源很少,但大量的僵尸进程会耗尽系统的进程表条目,从而影响系统性能和稳定性。
如何回收僵尸进程?
-
使用wait()或waitpid(): 父进程可以调用wait()或waitpid()函数来等待子进程终止,并获取它的终止状态。这将使操作系统从进程表中删除对应的僵尸进程条目。
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程代码 _exit(0); } else if (pid > 0) { // 父进程代码 wait(NULL); // 等待子进程终止 } else { // fork失败 perror("fork"); } return 0; }
-
处理SIGCHLD信号: 父进程可以通过捕获SIGCHLD信号来处理子进程终止事件,并调用waitpid()来避免僵尸进程的产生。
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #include <stdio.h> void sigchld_handler(int signum) { // 使用非阻塞方式调用waitpid(),防止阻塞父进程 while (waitpid(-1, NULL, WNOHANG) > 0); } int main() { struct sigaction sa; sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGCHLD, &sa, NULL); pid_t pid = fork(); if (pid == 0) { // 子进程代码 _exit(0); } else if (pid > 0) { // 父进程代码 sleep(10); // 模拟父进程的工作 } else { // fork失败 perror("fork"); } return 0; }
-
daemon进程: 将父进程设计成守护进程(daemon),这样孤儿进程会被init进程(PID 1)领养,而init进程会自动回收孤儿进程,避免僵尸进程的产生。
通过这些方法,可以有效地回收僵尸进程,保持系统的稳定性和高效性