좀비 프로세스 생성과 소멸
좀비 프로세스는 껍데기만 남아있는 상태이다
좀비 프로세스란?
- zombie process, defunct process라고도 한다
- 실행이 종료되었지만 os의 process table을 점유하고 있는 프로세스
- os가 관리하는 process table의 크기에는 제한이 있기 때문에 좀비 프로세스가 계속 생성되면 더 이상 프로세스 생성이 불가능할 수 있다
- parent가 자신의 exit status를 확인하기를 기다리고 있는 상태이다
- child의 exit status를 확인하는 방법에는 두 가지가 있다
example code
- child process는 defunct process가 되는 예제
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, const char *argv[])
{
pid_t p;
if ((p = fork()) == 0) // child
return 0;
else // parent
while (1) { sleep(10); }
return 0;
}
ps -ef | grep <프로세스 이름>실행 --> [프로세스 이름] \<defunct> 출력

좀비 프로세스 발생을 막는 방법
wait류 함수 호출- signal handler 등록
wait
- wait를 호출하면 child process의 main 함수가 반환한 값을 확인할 수 있다
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{
pid_t p;
int estatus;
if ((p = fork()) == 0) // child
return 99;
else { // parent
wait(&estatus);
printf("child(%d) exit status: %d\n",
p, estatus);
while (1) sleep(10);
}
return 0;
}
signal
- child의 main 함수가 반환하면 parent에게 SIGHLD signal이 전달되는데 이 시그널을 받았을때 waitpid로 종료된 child의 exit status를 읽을 수 있다
sigaction을 사용하면 signal에 대해signal함수보다 섬세한 제어가 가능하다. signal보다는 sigaction 사용이 권장된다signal함수는 핸들러가 실행되는 동안 새로운 시그널이 프로세스에 전달되는 것을 막지 않는다. 하지만sigaction은 시그널 핸들러가 반환하기 전까지 다른 시그널을 막는다(block)signal함수는 보통 시그널 핸들러가 한 번 호출되고 나면 해당 시그널에 대한 핸들러를SIG_DFL로 초기화한다- 근데 내 환경(6.8.0-48-generic #48~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64)에서는 시그널 핸들러가 유지됐다
signal함수의 위와 같은 동작은 UNIX 구현체마다 다르다. 표준이 이를 허용하고 있다
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#define DO_USEFUL_TASKS do { sleep(10); } while(1);
void sigchld_handler(int signo)
{
pid_t p;
int estatus;
int opt = 0;
waitpid(-1, &estatus, opt);
printf("child(%d) exit status: %d\n",
p, estatus);
}
int main(int argc, const char *argv[])
{
pid_t p;
int estatus;
if ((p = fork()) == 0) {// child1
printf("child(%d) exit\n", getpid());
return 1;
}
else { // parent
signal(SIGCHLD, sigchld_handler);
// signal(SIGCHLD, SIG_DFL); // 좀비 생성
// signal(SIGCHLD, SIG_IGN); // 좀비 생성 안됨
}
if ((p = fork()) == 0) {// child2
printf("child(%d) exit\n", getpid());
return 2;
}
DO_USEFUL_TASKS
return 0;
}
references
- [WIKIPEDIA] Zombie process
- [Quora] signal 함수보다 sigaction 함수를 써야하는 이유
- [Stackoverflow] signal vs sigaction