僵尸进程的产生方法
僵尸进程(Zombie Process)是指子进程已经终止,但其退出状态未被父进程回收(通过 wait() 或 waitpid() 系统调用),导致该进程的进程描述符仍然保留在系统中。以下是常见的僵尸进程产生方法:
父进程未调用 wait() 或 waitpid()
子进程结束后,父进程如果没有调用 wait() 或 waitpid() 回收子进程的状态信息,该子进程就会变成僵尸进程。
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
printf("Child process exiting\n");
return 0; // 子进程退出
} else {
printf("Parent process running\n");
sleep(30); // 父进程不回收子进程
}
return 0;
}
父进程被信号中断
如果父进程被某个信号(如 SIGKILL)中断,导致无法正常执行 wait(),其子进程可能会变成僵尸进程。
父进程未处理 SIGCHLD 信号
默认情况下,父进程会忽略 SIGCHLD 信号,但如果父进程显式设置了 SIG_IGN,系统会自动回收子进程,不会产生僵尸进程。相反,如果父进程没有正确处理 SIGCHLD,子进程可能会滞留。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main() {
signal(SIGCHLD, SIG_IGN); // 忽略 SIGCHLD,不会产生僵尸进程
pid_t pid = fork();
if (pid == 0) {
printf("Child process exiting\n");
return 0;
} else {
printf("Parent process running\n");
sleep(30);
}
return 0;
}
父进程持续运行但不回收子进程
某些情况下,父进程可能长期运行但不主动回收子进程,导致系统中积累大量僵尸进程。
#include <stdio.h>
#include <unistd.h>
int main() {
for (int i = 0; i < 5; i++) {
pid_t pid = fork();
if (pid == 0) {
printf("Child %d exiting\n", i);
return 0;
}
}
printf("Parent process running\n");
sleep(60); // 不回收任何子进程
return 0;
}
僵尸进程的查看方法
可以通过 ps 命令查看系统中的僵尸进程:
ps aux | grep 'Z'
输出示例:
| USER | PID | STAT | COMMAND |
|---|---|---|---|
| root | 1234 | Z | [child] |
其中 STAT 列显示 Z 表示僵尸进程。
如何避免僵尸进程
- 父进程主动调用
wait()或waitpid()回收子进程。 - 父进程设置
SIGCHLD信号处理函数为SIG_IGN,让系统自动回收子进程。 - 使用双
fork技巧,让子进程被init进程接管(PID=1)。
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
pid_t grandchild = fork();
if (grandchild == 0) {
printf("Grandchild process running\n");
sleep(5);
printf("Grandchild exiting\n");
return 0;
} else {
printf("Child process exiting\n");
return 0; // 子进程退出,孙子进程由 init 接管
}
} else {
wait(NULL); // 父进程回收子进程
printf("Parent process done\n");
}
return 0;
}
通过以上方法,可以有效模拟僵尸进程的产生,并了解如何避免它们。