What is a Zombie Process in Linux
A zombie process (zombie process) is a process that has already finished its execution, but its entry remains in the system's process table. This happens when the parent process fails to read the child's exit status using the wait() system call or one of its variants.
In the output of commands like ps aux or top, such a process is displayed with the status Z. A zombie process consumes no CPU time or RAM, but it occupies an entry in the process table (and therefore one of the available process identifiers — PID).
Usually, a zombie process is a temporary state that lasts microseconds. However, if the parent process "forgets" about its child, the zombie can remain in the system indefinitely.
What does the error look like?
$ ps aux | grep Z
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1234 0.0 0.0 0 0 ? Z 10:00 0:00 [defunct] <process_name>
The [defunct] symbol in the COMMAND column clearly indicates a zombie process.
Causes
Zombie processes appear due to one primary cause and several indirect ones:
- The parent process does not call
wait(). This is the most frequent cause. After the child process terminates (e.g., viaexit()), the kernel stores information about its termination (return code, resource usage) in the process structure. The parent must read this information usingwait()orwaitpid(). If the parent fails to do so, the child's entry remains in the process table as a "zombie". - The parent process is "hung" or mishandles signals. If the parent process ignores the
SIGCHLDsignal (which the kernel sends upon a child's termination) or terminates itself without waiting for its children, this leads to a zombie. - A programming error. The parent process code might lack a
wait()call afterfork(), or it could be blocked on another action (e.g., waiting for I/O). - An error in a system script or daemon. Some old or poorly written daemons can create zombies when handling requests.
How to Eliminate Zombie Processes
Since a zombie process is already dead, it cannot be "killed". The only way to free its entry in the process table is to make the parent process read the exit status. If the parent is unable or unwilling to do this, you must terminate the parent itself.
Method 1: Send a SIGCHLD Signal to the Parent Process
This is the cleanest method. The SIGCHLD signal (child termination signal) can cause a parent process that handles it correctly to invoke wait() and "reap" the zombie.
- Find the zombie process's parent process ID (PPID) (from the
ps auxoutput). - Send it the signal:
or simply:kill -SIGCHLD <PPID>kill -18 <PPID> - Check if the zombie is gone:
ps aux | grep 'Z'.
⚠️ Important: Many programs do not have a custom handler for
SIGCHLDby default. In this case, the kernel simply ignores the signal, and the zombie will remain.
Method 2: Terminate the Parent Process
If the signal didn't help, the most reliable method is to terminate the parent process. After this, the zombie process becomes an "orphan" and is inherited by the special init process (PID 1) or systemd (on modern systems). The init process periodically executes wait() for all its child processes, so the zombie will be automatically cleaned up.
- Ensure the parent's PID (PPID) is correct and you are prepared to terminate it. Caution: Terminating a system process (e.g.,
sshd,cron) may cause temporary service unavailability. - Send a termination signal:
If the process does not respond, use forceful termination:kill <PPID>kill -9 <PPID> - After terminating the parent, check the process list. The zombie should be gone.
Method 3: Restart the Parent Process (if it's a Service)
If the parent process is a system daemon (e.g., apache2, nginx, mysql), the correct solution is to restart it via the service manager.
For systemd:
sudo systemctl restart <service_name>
For SysVinit (older systems):
sudo service <service_name> restart
Restarting the service guarantees that a new instance of the parent process will begin correctly managing its child processes.
Method 4: Debug and Fix the Source Code (for Developers)
If zombie processes constantly appear in your own application, you need to fix its code.
- Locate places in the parent process code that come after
fork(). - Ensure that immediately after
fork()in the parent branch, there is a call towait()orwaitpid()to collect the child's exit status. - If the parent must run concurrently with the child, you need to:
- Set up a handler for the
SIGCHLDsignal usingsignal()orsigaction(). - Inside the handler, call
waitpid()in a loop (to reap all terminated children). - Or periodically (with a non-blocking call) check for terminated children.
- Set up a handler for the
Example of a correct handler in C:
#include <sys/wait.h>
#include <signal.h>
void sigchld_handler(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
// In main(): signal(SIGCHLD, sigchld_handler);
Prevention
To avoid the accumulation of zombie processes in the future:
- For system administrators: Regularly check the process list for zombies (
ps aux | grep 'Z'), especially after starting/stopping critical services. If zombies appear due to a specific daemon, look for updates for that software or report a bug to the developers. - For developers:
- Always handle the
SIGCHLDsignal in parent processes that create children viafork(). - Use a non-blocking
waitpid(-1, &status, WNOHANG)call in a loop inside the handler to reap all terminated children. - Consider using higher-level constructs (e.g.,
subprocessin Python, which automatically collects exit statuses) instead of directfork/exec.
- Always handle the
- Monitoring: Set up a simple script to monitor the number of zombie processes and alert if it exceeds, for example, 10.
#!/bin/bash ZOMBIE_COUNT=$(ps aux | grep -c ' Z ') if [ "$ZOMBIE_COUNT" -gt 10 ]; then echo "Warning: $ZOMBIE_COUNT zombie processes detected!" | wall # You can also add email sending or a PagerDuty call fi
Conclusion
Zombie processes in Linux are primarily a consequence of errors in parent programs, not a critical system problem. They consume negligible resources, but their accumulation indicates malfunctioning software. In most cases, simply terminating the zombie's parent process is enough, after which the kernel will clean up its entry automatically. For a permanent fix, developers need to correct the code, while administrators should monitor service health and keep software updated.