Fundamentals 8 min read

Understanding Linux Zombie Processes and How to Prevent Them

This article explains what zombie processes are in Linux, how they are created when a child exits without its parent calling wait, demonstrates their detection with ps, provides sample C code to reproduce and handle them, and shows techniques to avoid their accumulation.

ITPUB
ITPUB
ITPUB
Understanding Linux Zombie Processes and How to Prevent Them

In Linux, a zombie process is a terminated child that remains in the process table because its parent has not yet retrieved its exit status; the kernel keeps minimal information such as the PID, exit code, and CPU usage for the parent to collect.

The typical creation sequence is: a parent calls fork() to create a child, the child runs and calls exit(), its descriptor stays in memory with state EXIT_ZOMBIE, and the kernel sends a SIGCHLD signal to the parent. If the parent never invokes wait() or waitpid(), the zombie persists until the parent exits.

You can observe zombies with commands like ps aux | grep -w 'Z', which marks them with the state ‘Z’. Example output shows a defunct process named zombie after running a sample program.

Example program that creates a zombie:

#include <stdio.h>
#include <sys/types.h>
int main(){
    // fork a child process
    pid_t pid = fork();
    if (pid > 0) { // parent
        printf("in parent process, sleep for one minute...zZ...
");
        sleep(60);
        printf("after sleeping, and exit!
");
    } else if (pid == 0) { // child
        printf("in child process, and exit!
");
        exit(0);
    }
    return 0;
}

Because the parent never calls wait(), the child remains a zombie until the parent finishes sleeping and exits.

When the parent terminates, all of its orphaned children are adopted by the init process (PID 1). init periodically calls wait() on its children, automatically reaping any zombies, which is why the zombie disappears after the parent exits.

Preventing zombie processes

Instead of killing a zombie (which is impossible because it is already dead), install a handler for SIGCHLD that calls wait() to clean up terminated children. The following code demonstrates this approach:

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

sig_atomic_t child_exit_status;

void clean_up_child_process(int signal_num) {
    int status;
    wait(&status);
    child_exit_status = status;
}

int main(){
    struct sigaction sigchild_action;
    memset(&sigchild_action, 0, sizeof(sigchild_action));
    sigchild_action.sa_handler = &clean_up_child_process;
    sigaction(SIGCHLD, &sigchild_action, NULL);

    pid_t c_pid = fork();
    if (c_pid > 0) {
        printf("in parent process, and sleep for one minute...zZ...
");
        sleep(60);
    } else if (c_pid == 0) {
        printf("in child process, and exit now
");
        exit(0);
    } else {
        printf("fork failed!
");
    }
    return 0;
}

With the signal handler, the parent immediately reaps the child when it terminates, preventing the zombie from persisting.

Zombie process illustration
Zombie process illustration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

process managementCsignal handlingzombie process
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.