grep

Engineering

Zombie 프로세스를 좀처럼 볼 수 없는 이유?

NHN

2019년 9월 19일

원문에서 보기 ↗

새로운 프로세스를 만들 때 리눅스에서는 fork()를 사용합니다. fork()를 통해서 부모 프로세스는 자식 프로세스를 생성하고, 자식 프로세스에서 실제 실행하려는 프로그램을 exec()을 통해서 실행합니다.

자식 프로세스가 exit()를 호출하고 죽으면, 부모 프로세스는 waitpid()를 명시적으로 호출해서, 이 자식 프로세스의 exit 값을 가져가야 합니다.

자식 프로세스가 exit()를 호출하였으나, 부모 프로세스가 waitpid()로 자식 프로세스의 pid를 수거(reaping) 하지 않은 경우에, 이 자식 프로세스는 zombie 상태가 됩니다.

$ ps -e -o pid,stat,comm | grep a.out
32499 S+   a.out
32500 Z+   a.out <defunct>

하지만 이런 zombie 프로세스는 좀처럼 볼 수 없습니다. 보통은 부모 프로세스가 waitpid로 잘 처리하도록 잘 짜여 있기 때문입니다.

또는 이런 zombie 프로세스가 생기더라도, 부모 프로세스가 종료되면 커널은 이 zombie 프로세스를 init(또는 systemd) 프로세스의 자식으로 입양시키게 됩니다. init이나 systemd는 주기적으로 waitpid()를 통해서 zombie 프로세스의 눈을 감겨줍니다. (https://en.wikipedia.org/wiki/Zombie_process 참조)

이런 상황을 볼 때, 여러분이 zombie 프로세스를 볼 수 있는 상황은 딱 2개입니다.

  1. 부모 프로세스가 살아 있으면서도 명시적으로 자식 프로세스에 대해 waitpid 호출하지 않는 경우,
  2. systemd나 init이 ~~맛이 가서~~오동작을 해서 zombie 프로세스를 제대로 회수하지 않는 경우,

zombie를 직접 보고 싶으시면 아래 코드를 이용하세요. 컴파일 후 실행하고 5초 뒤에 ps로 해당 바이너리 상태를 보시면 됩니다.

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main()
{
    int pid;
    int status;
    pid = fork();

    //signal(SIGCHLD, SIG_IGN);

    if (pid == 0)
    {
        sleep(5);
        printf("I will be back %d\n", getpid());
        exit(0);
    }
    else if(pid > 0)
    {
        printf("Im parent %d\n", getpid());
        printf("Press any key\n");
        getchar();
/*
        while(1)
        {
            printf("Im sleeping\n");
            sleep(1);
        }
*/
    }
    else
    {
        perror("fork error :");
    }
}

위 코드는 https://www.joinc.co.kr/w/Site/system_programing/process/Zombie 에서 가져왔습니다.