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.
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.
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.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
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.
