Fundamentals 13 min read

Understanding Linux Process States: From Zombies to Orphans and How to Handle Them

Learn what Linux processes are, explore their various states—including running, ready, blocked, zombie, and orphan—understand how PID and PPID work, and discover practical C code examples and signal‑handling techniques to prevent and clean up zombie processes safely.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Understanding Linux Process States: From Zombies to Orphans and How to Handle Them

Process Overview

A process is an executing instance of a program. The operating system treats it as the basic unit for resource allocation and scheduling. Each process has a unique PID and a parent PID (PPID) that is reclaimed when the process terminates.

Process States

Typical states are running , ready , blocked and suspended . When memory is scarce, ready or blocked processes may be swapped out to disk, entering a suspended state. The system assigns CPU time based on priority and time‑slice rotation.

Zombie (defunct) Processes

A zombie appears when a child exits but its parent has not yet called wait() (or waitpid()) to read the child's exit status. The child's PCB remains in the process table, shown as <defunct> by ps.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {               // child
        printf("child id is %d
", getpid());
        printf("parent id is %d
", getppid());
    } else {                      // parent stays alive, child becomes zombie
        while (1) {}
    }
    exit(0);
}

Run the program in the background and use ps; the child appears with a <defunct> tag, confirming the zombie state.

Orphan Processes

An orphan occurs when a parent terminates before its child. The init process (PID 1) adopts the orphan and later reaps it, so orphans do not consume resources.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {               // child
        printf("child ppid is %d
", getppid());
        sleep(10);                // let parent exit first
        printf("child ppid is %d
", getppid());
    } else {                      // parent
        printf("parent id is %d
", getpid());
    }
    exit(0);
}

After the parent exits, the child's PPID becomes 1, showing that init has adopted it.

Handling Zombie Processes

Using a SIGCHLD handler

Register a handler for SIGCHLD. When the kernel sends the signal after a child exits, the handler calls wait() to reap the zombie.

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

void deal_child(int sig) {
    printf("deal_child entered
");
    wait(NULL);                 // reap one child
}

int main() {
    signal(SIGCHLD, deal_child);
    pid_t pid = fork();
    if (pid == 0) {               // child
        printf("child is running
");
        sleep(2);
        printf("child will end
");
    } else {                      // parent
        sleep(1);
        printf("parent is running
");
        sleep(10);
        printf("sleep 10 s over
");
        sleep(5);
        printf("sleep 5 s over
");
    }
    exit(0);
}

Robust cleanup with waitpid()

If many children terminate quickly, some SIGCHLD signals may be lost. A non‑blocking loop with waitpid(-1, NULL, WNOHANG) ensures that all zombies are collected.

void deal_child(int sig) {
    for (;;) {
        if (waitpid(-1, NULL, WNOHANG) == 0)
            break;               // no more zombies
    }
}

Signal Basics

The signal(int signum, void (*handler)(int)) function registers a handler for a specific signal. The second argument can be: SIG_IGN – ignore the signal. SIG_DFL – perform the default action (usually termination).

A pointer to a user‑defined function returning void and accepting an int (the signal number).

Properly combining signal() with wait() or waitpid() prevents zombie accumulation and keeps the system stable.

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 managementsignal handlingzombie processOrphan Process
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

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.