Unlocking Linux Process States: From Zombies to Orphans
This article explains Linux process lifecycle, detailing the five classic states, how the kernel represents them, practical commands and C code to observe state transitions, and deep dives into zombie and orphan processes with real‑world examples and mitigation techniques.
Process States Overview
Operating systems classify a process into five major states: new (just created), ready (waiting for CPU), running (currently executing), blocked (waiting for I/O or other events), and terminated (finished or killed).
New state : the process has just been created, its PCB and memory are allocated but it has not entered the ready queue.
Ready state : all resources except the CPU are allocated; the scheduler can dispatch it immediately.
Blocked state : the process is waiting for an event (e.g., I/O) and cannot run even if the CPU is assigned.
Running state : the process holds the CPU and is executing.
Terminated state : the process has finished normally, exited with an error, or been killed.
Running State and the Runqueue
When many processes compete for a single CPU, the scheduler maintains a runqueue per CPU. Each entry is a task_struct (the PCB). The scheduler picks a task from the queue, removes it, and places it on the CPU.
To prevent a single process from monopolising the CPU, the kernel assigns each process a time slice; when the slice expires, the process is pre‑empted and placed at the tail of the runqueue.
Blocked State
When a process needs a device that is not ready, it is placed on the device’s wait queue. Once the device becomes ready, the process is moved back to the ready queue.
Suspended (Swapped‑out) State
If many processes are waiting for a device and memory is scarce, the kernel can swap a process’s code and data to disk, leaving only its PCB in memory. The process is then in a suspended state, freeing RAM for other tasks.
Linux Kernel Representation
/*
* The task state array is a strange "bitmap"
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)",/* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)",/* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};R (running) : the task is either executing or ready in the runqueue.
S (sleeping) : the task is waiting for an event (interruptible sleep).
D (disk sleep) : uninterruptible sleep, typically waiting for I/O.
T (stopped) : stopped by a signal (e.g., SIGSTOP); can be resumed with SIGCONT.
t (tracing stop) : stopped while being traced (debugger breakpoint).
X (dead) : a transient state not shown in task listings.
Z (zombie) : exited but not yet reaped by its parent.
Observing Process States with Code
Example 1 – a busy loop that prints continuously:
int main()
{
while(1)
{
printf("hello linux
");
}
return 0;
}Because the program constantly performs I/O, it often appears in the S (sleeping) state.
Example 2 – the same loop without any I/O:
int main()
{
while(1);
return 0;
}Without I/O the process stays in the R (running) state.
Foreground processes are shown with a + in the ps output; appending & runs them in the background. To kill a process, use kill -9 PID.
Stopping and Continuing a Process
Send kill -19 759 (SIGSTOP) to pause a process, then kill -18 759 (SIGCONT) to resume it. After stopping, the process shows the T state.
Zombie Processes
A child that exits before its parent becomes a Z (zombie) state. Its task_struct remains until the parent calls wait() or waitpid() to reap it. If the parent never reaps the child, the zombie persists and wastes memory.
Orphan Processes
If a parent exits before its child, the child is adopted by PID 1 (the init process) and becomes an orphan. Orphans are later reaped by init, preventing them from staying in Z indefinitely.
#include <iostream>
#include <unistd.h>
#include <cstdlib>
using namespace std;
int main()
{
pid_t id = fork();
if(id == 0) {
int cnt = 500;
while(cnt) {
printf("i am child, pid:%d, ppid:%d, cnt:%d
", getpid(), getppid(), cnt);
cnt--;
sleep(1);
}
printf("child quit!
");
exit(0);
} else {
int cnt = 5;
while(cnt) {
printf("i am parent, pid:%d, ppid:%d, cnt:%d
", getpid(), getppid(), cnt);
sleep(1);
cnt--;
}
printf("parent quit!
");
}
return 0;
}When the parent finishes, the child’s parent becomes PID 1, making it an orphan that the system will eventually clean up.
Summary
The article walks through Linux process states, how the kernel records them, practical commands and C examples to observe state changes, and the special cases of zombie and orphan processes, providing insight into how the OS manages and reclaims resources.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
