Linux:进程等待究竟是什么?如何解决子进程僵尸所带来的内存泄漏问题?
在Linux系统中,当一个父进程创建了一个子进程,并且子进程结束了,但是父进程没有通过调用wait()
或者waitpid()
系统调用来获取子进程的状态,那么子进程的进程描述符就会保留在系统中,这样的子进程称为僵尸进程(Zombie Process)。僵尸进程会占用进程表中的一个位置,如果有大量的僵尸进程积累,最终可能导致进程表满,进而导致无法创建新的进程。
解决方法:
- 通过信号机制:父进程可以通过设置信号处理函数,当子进程结束时,父进程会收到
SIGCHLD
信号,然后在信号处理函数中调用wait()
或waitpid()
来清理子进程。 - 使用
waitpid()
函数的WNOHANG
选项:父进程可以通过定期调用waitpid()
并传递WNOHANG
选项来检查是否有已经结束的子进程需要清理,如果没有结束的子进程,则该调用会立即返回,不会阻塞父进程。 - 系统级别的解决方案:可以通过设置父进程的
SIGCHLD
信号处理为SIG_IGN
,这样内核会自动清理僵尸进程。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void reap_child(int sig) {
wait(NULL); // 清理僵尸进程
}
int main() {
pid_t pid;
// 安装信号处理函数
struct sigaction sa;
sa.sa_handler = &reap_child;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGCHLD, &sa, NULL);
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork failed");
exit(EXIT_FAILURE);
}
if (pid > 0) {
// 父进程
printf("Parent process, PID: %d\n", getpid());
} else {
// 子进程
printf("Child process, PID: %d\n", getpid());
sleep(5); // 模拟子进程运行
exit(EXIT_SUCCESS); // 子进程结束
}
return 0;
}
在这个示例中,父进程安装了一个信号处理函数reap_child
,当接收到SIGCHLD
信号时,会在信号处理函数中调用wait()
来清理僵尸进程。这样就可以避免子进程成为僵尸进程所带来的问题。
评论已关闭