Linux Zombieプロセスのステータスの説明とクリーンアップ方法

5098 ワード

Linuxプロセスの状態


psのヘルプマニュアルでは、プロセスにいくつかのステータスが表示されます
man ps
               D    uninterruptible sleep (usually IO)
               R    running or runnable (on run queue)
               S    interruptible sleep (waiting for an event to complete)
               T    stopped, either by a job control signal or because it is being traced
               W    paging (not valid since the 2.6.xx kernel)
               X    dead (should never be seen)
               Z    defunct ("zombie") process, terminated but not reaped by its parent

プロセス_exitが終了すると、プロセスが消費するメモリやその他のリソースが回収され、オペレーティングシステムのprocess tableに記録(PID、termination status、resource usage information)が保持されます.このとき、プロセスの状態はzombie/defunctです.
親プロセスはwaitpidシステム呼び出しを使用してzombie状態のサブプロセスを回収し、回収後のプロセスの情報はprocess tableから除去されます.Wikiの例
#include 
#include 
#include 

int main(void)
{
    pid_t pids[10];
    int i;

    for (i = 9; i >= 0; --i) {
        pids[i] = fork();
        if (pids[i] == 0) {
            sleep(i+1);
            _exit(0);
        }
    }

    for (i = 9; i >= 0; --i)
        waitpid(pids[i], NULL, 0);

    return 0;
}

man 2 waitの解釈
       A child that terminates, but has not been waited for  becomes  a  "zom-
       bie".  The kernel maintains a minimal set of information about the zom-
       bie process (PID, termination status, resource  usage  information)  in
       order to allow the parent to later perform a wait to obtain information
       about the child.  As long as a zombie is not removed  from  the  system
       via  a wait, it will consume a slot in the kernel process table, and if
       this table fills, it will not be possible to create further  processes.
       If a parent process terminates, then its "zombie" children (if any) are
       adopted by init(8), which automatically performs a wait to  remove  the
       zombies.

zombieプロセスの親プロセスがterminateされた場合、zombieプロセスはinitプロセスによって引き継がれ、initプロセスもzombieにあるプロセスを非同期で呼び出すwait回収を呼び出す.

いつZombie状態に入りますか


前に説明したように、プロセスexit後、zombie状態に入ります.その後、親プロセスはwaitpid呼び出しによりzombie状態のプロセスを回収します.zombieステータスプロセスの親プロセスがterminateされると、回収されていないzombieプロセスがinitに引き継がれ、initはwaitpidを呼び出してzombieサブプロセスを回収します.
なお、POSIX.1-2001標準のシステム、SIGCHLD to SIG_の設定を許可するIGNは、waitによってzombieサブプロセスを回収する必要がない.forkのサブプロセスプロセスはzombie状態に入らないため、exit後にprocess tableに情報は保持されません.
On modern UNIX-like systems (that comply with SUSv3 specification in this respect), the following special case applies: if the parent explicitly ignores SIGCHLD by setting its handler to SIG_IGN (rather than simply ignoring the signal by default) or has the SA_NOCLDWAIT flag set, all child exit status information will be discarded and no zombie processes will be left

       POSIX.1-1990 disallowed setting the  action  for  SIGCHLD  to  SIG_IGN.
       POSIX.1-2001  allows  this possibility, so that ignoring SIGCHLD can be
       used to prevent the creation of zombies (see  wait(2)).   Nevertheless,
       the  historical BSD and System V behaviors for ignoring SIGCHLD differ,
       so that the only completely portable method of ensuring that terminated
       children  do not become zombies is to catch the SIGCHLD signal and per-
       form a wait(2) or similar.

Zombieステータスのプロセスをクリーンアップする方法


zombieプロセスの親プロセスによりwaitpid呼び出しを開始し、process table内の対応するサブプロセスの情報をクリーンアップします.親プロセスが処理されていない場合は、SIGCHLD信号を手動で開始し、処理させることができます.
kill -SIGCHLD $(ps -A -ostat,ppid | awk '/[zZ]/{print $2}')

この信号を送るのがまだだめなら、parentプロセスがこの信号を処理していない可能性があります.親プロセスも乾かして、initにzombieプロセスを回収させます.

掃除しないと何か危険がある


zombieプロセスはprocess tableのslotを占有し、非常に多くのzombieがある場合、最終的にはprocess table slotがいっぱいになり、システムが新しいプロセスを作成できない可能性があります.

リファレンス


http://stackoverflow.com/questions/16944886/how-to-kill-zombie-processhttps://manpages.debian.org/cgi-bin/man.cgi?query=wait&sektion=2https://en.wikipedia.org/wiki/Zombie_processhttp://unix.stackexchange.com/questions/11172/how-can-i-kill-a-defunct-process-whose-parent-is-inithttp://stackoverflow.com/questions/20535438/cant-cleanup-a-zombie-process-whose-parent-is-initman 2 exitman 2 waitman 7 signal

PostgreSQLが終了したサブプロセスをどのように処理するか


waitpidの影も見えます
          
src/backend/postmaster/postmaster.c:    pqsignal(SIGCHLD, reaper);      /* handle child termination */

        
/*
 * Reaper -- signal handler to cleanup after a child process dies.
 */
static void
reaper(SIGNAL_ARGS)
{
        int                     save_errno = errno;
        int                     pid;                    /* process id of dead child process */
        int                     exitstatus;             /* its exit status */

        PG_SETMASK(&BlockSig);

        ereport(DEBUG4,
                        (errmsg_internal("reaping dead processes")));

        while ((pid = waitpid(-1, &exitstatus, WNOHANG)) > 0)
        {
...