Detailed explanation of zombie process and orphan process in PHP

Keywords: PHP Unix

Zombie process

When the child process finishes running, the parent process continues to run, but the parent process does not recycle the child process, freeing the resources occupied by the child process, then the child process becomes a zombie process.

In Unix process management, if the new child process is finished, the parent process will receive a SIGCHLD signal, and the child process will temporarily become a zombie process, waiting for the parent process to process. If the parent process does not process all the time, the process will always exist, occupy the system process table entries, and become a zombie process permanently. If there are too many zombie processes, the system will not be able to run other applications without available process table entries.

<?php
$str = "hello world!" . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) {
    echo "I am the main process, id yes" . getmypid() . ",Subprocess's pid yes{$pid}" . PHP_EOL;
    pcntl_async_signals(true);
    pcntl_signal(SIGCHLD, function () {
        echo 'Subprocess exited, please handle in time' . PHP_EOL;
    });
    while (1) {  //Simulate the main process running all the time
        sleep(1);
    }
} elseif($pid==0) {
    echo "I'm a subprocess, my pid yes". getmypid() ."\n";
}else{
    echo "I am the main process, failed to open the child process\n";
}

Use ps to view the zombie process:

ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'

The terminal will output:

Z+     7136   7137 [php] <defunct>

When the main process exits, the child process will be taken over by init and processed

Using pcntl_wait recycle zombie process:

<?php
echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) {  //Main process code
    pcntl_wait($status);  //Parent process blocking mode waiting for child process to exit
    echo time() . PHP_EOL;
} elseif($pid==0) {
    sleep(3);
    echo "I'm a subprocess, my pid yes". getmypid() ."\n";
    exit();
}else{
    die("I am the main process, failed to open the child process\n");
}
1589874657
 I am a subprocess, my pid is 16140
1589874660

pcntl_wait($status); the default is blocking mode recycling subprocess. You can set the second parameter to WNOHANG, which is non blocking mode recycling subprocess. The code will continue to execute, and the subprocess will be recycled automatically after exiting.

Multiple subprocesses only need one pcntl_wait to recycle.

In the parent process, configure the handler for SIGCHLD to recycle:

<?php
pcntl_async_signals(true);

pcntl_signal(SIGCHLD, function () {
    echo "SIGCHLD" . PHP_EOL;
    pcntl_wait($status);  //Parent process blocking mode waiting for child process to exit
});

echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) {  //Main process code
    sleep(10);
    echo time() . PHP_EOL;
} elseif($pid==0) {
    sleep(3);
    echo "I'm a subprocess, my pid yes". getmypid() ."\n";
    exit;
}else{
    die("I am the main process, failed to open the child process\n");
}
1589874039
 I am a subprocess, my pid is 12875
SIGCHLD
1589874040

Ignore the subprocess end signal and recycle by init:

<?php
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);

echo time() . PHP_EOL;
$pid = pcntl_fork();
if ($pid > 0) {  //Main process code
    sleep(10);
    echo time() . PHP_EOL;
} elseif($pid==0) {
    sleep(3);
    echo "I'm a subprocess, my pid yes". getmypid() ."\n";
    exit;
} else {
    die("I am the main process, failed to open the child process\n");
}
1589874331
1589874331
 I am a subprocess, my pid is 14493

Orphan process

Orphan process is a kind of process that continues to run after the execution of its parent process is completed or terminated. These orphan processes will be adopted by the init process and recycled by the init process.

Orphan process has no harm, just pay attention to its own code logic.

<?php
$pid = pcntl_fork();
if ($pid == -1) {
    die('fork error');
} elseif ($pid > 0) {
    echo "Dad left first,Son, you work hard" . PHP_EOL;
    exit();     // The main process has exited in a short time
} else {
    // Subprocess continues to run
    $i = 10;
    while($i) {
        echo $i;
        $i--;
        sleep(1);
    }
}
Dad left first, son. You work hard
1111111111...

The difference between orphan process and zombie process

Zombie process: a subprocess exits before its parent process calls wait() or waitpid(). This subprocess is a zombie process. After any sub process exits, it does not disappear immediately, but leaves a data structure called zombie process, waiting for the parent process to process. This is the stage that each subprocess goes through at the end. If the child process exits and the parent process fails to handle it, the child process will not be released and its process number will be occupied all the time. However, the system can only use a limited process number. If a large number of zombie processes are generated, the system will not be able to generate new processes because there is no available process number. This is the harm of zombie process and should be avoided.

Orphan process: if a parent process exits while one or more of its child processes are still running, those child processes will become orphan processes. Orphan processes will be adopted by the init process and recycled by the init process. Whenever an orphan process appears, the kernel sets the parent process of the orphan process to init, and the init process will wait for the child process that () has exited circularly. In this way, when an orphan process ends its life cycle, the init process will recycle. So the orphanage process is not going to be any harm.

Posted by move3rd on Thu, 21 May 2020 00:31:00 -0700