Check the health and availability of your Linux servers for optimal performance with Site24x7's Linux monitoring tool.
Zombie processes in Linux operating systems are more common than you may think. And while they may sound spooky, they’re more of a nuisance than a horror story. In essence, a zombie process (also called a defunct process) is a child process that has finished its execution, but is still present in the system’s process table because its parent process is yet to acknowledge its completion. This can lead to confusion and clutter, and over time even have an impact on system resources.
In this guide, we will share practical tips and tricks to identify, understand, and kill zombie processes in your Linux environment. We will also include some best practices to prevent zombie processes from occurring.
In Linux operating systems, when a child process has done its job, it sends the SIGCHLD signal to its parent process to indicate that it has terminated. The parent process is then responsible for receiving and acknowledging the signal, as well as collecting information about the exit status of the child process through system calls like wait() or waitpid(). This allows them to:
Only when the parent process collects this information does the operating system remove the entry of the child process from the process table. However, this “parent acknowledgement at time of death” process can sometimes fail, leading to the creation of zombie processes. Here are some of the main reasons this occurs g:
Even though the terms “zombie processes” and “orphaned processes” are often used interchangeably, they are not the same thing. Here is how the two compare:
While zombie processes may seem harmless at first glance, they can cause problems if left unchecked. Here are a few reasons why you should be vigilant about removing them:
One zombie process has minimal impact on the system, as the only resource it holds is its entry in the process table, known as its PID (process ID). However, when zombies accumulate over time, they can strain the process table. The process table is a vital resource with limited capacity. As long as zombie processes persist, the operating system can’t reassign their PIDs to other processes. In certain cases, this can restrict the system's ability to create new processes, leading to adverse effects.
Even though zombie processes themselves may not execute code, they occupy system resources and can be exploited by adversaries to hide malicious activities. For example, adversaries could potentially disguise their malicious processes as zombies, making it harder for system administrators to identify and mitigate ongoing security threats.
The presence of zombie processes typically means that your applications are not managing resources properly. This is why zombie processes are often considered a symptom of larger underlying issues within the system. For example, a high number of long-running zombie processes may indicate that several of your applications are unresponsive, potentially leading to service unavailability.
Regular monitoring and maintenance of system processes is widely considered a best practice for system administration. Identifying and troubleshooting zombie processes in a timely manner aligns with this best practice, enabling system administrators to uphold system integrity, security, and performance.
Now that we know just how important it is to mitigate zombie processes, let’s look at some handy commands and tools to identify them:
Here are some variants of the ps command that you can use to check for zombies:
ps auxf
This command displays all processes (a), detailed information (x), and filters by user (u), process ID (x), and format (f).Look for the Z in the STAT column to identify zombies.
ps -eAo state,pid,comm
This command offers a leaner format focusing on the STATE (Z for zombies), PID (process ID), and COMMAND name.
ps -eAo state,pid,comm | grep -w Z
This command allows us to refine the output of the previous command even more. We are using grep to filter the output, ensuring we are shown only the processes that have a state of Z – i.e., zombie processes.
The top utility allows for real-time monitoring. To view zombie processes using it, run this command:
top -b | grep 'Z'
The -b flag updates the display continuously, and grep 'Z' filters for lines with Z in the STAT column. Once you run this command, you should be able to see zombie processes in real time, as they are created on your system.
htop is an interactive process viewer that is similar to top, but with additional features and a more user-friendly interface. Run the htop command and then hit the F4 key to apply a filter and identify zombie processes.
The pgrep command can also be used to list the PIDs of processes based on criteria like process name or state. To find zombie processes with pgrep, use the following command:
pgrep -fl Z
To enhance our understanding of the concept, let’s try to simulate a zombie process. Once the zombie process has been created, we will use a command from the previous sections to check for its existence. The zombie process will automatically be reaped once our experiment finishes.
Create a new file named temp.c and copy the following code to it:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t child_pid;
// Create a child process
child_pid = fork();
if (child_pid < 0) {
// Fork failed
perror("fork");
exit(EXIT_FAILURE);
} else if (child_pid == 0) {
// Child process
printf("Child process is running.\n");
// Child process exits immediately
} else {
// Parent process
printf("Parent process is running.\n");
// Parent process sleeps for a while. During this time the child may
become a zombie
sleep(30);
}
return 0;
}
In the above code, we are creating a new child process using the fork() system call. The child process exits immediately after printing a line. Meanwhile, the parent process invokes the sleep() call to pause its execution for 30 seconds. During this period of dormancy, the parent process is unable to acknowledge the termination of the child process. Thus, the child process remains in a transitional state, temporarily labeled as a zombie.
However, once the parent’s sleep time (30 seconds) finishes, it acknowledges the child's termination. This reaps the child process from the process table.
Run the following command to compile the code.
gcc temp.c -o temp
Open another terminal window and run the following command to track the zombie process as it appears:
top -b | grep 'Z'
Go back to the original terminal window and run this command to execute the program:
./temp
As you run the above command, switch to the other terminal window and you should be able to see the new zombie process. Expect an output that shows the PID, status, and name of the program.
After the program exits, rerun the command from Step 3 and you should now see an empty output. This confirms that the zombie has been eliminated.
As zombies are already dead (by definition), we can’t kill them. However, we can eliminate them from the process table by killing their parents. But before you attempt to terminate a zombie’s parent, it’s often prudent to troubleshoot and address the root cause of the problem. This will help you prevent the zombie problem from recurring.
Here are some steps that you can take for zombie process troubleshooting on a Linux system:
ps -o ppid= -p <zombie_pid>
Once you have identified the root cause of the problem, you can kill the zombie’s parent to remove the zombie from the process table. Follow these steps:
Run the following command to get the zombie’s PID:
ps aux | grep -w Z
Run the following command to get the PID of the zombie’s parent:
ps o ppid [insert zombie PID here]
Run this command to terminate the zombie’s parent:
kill -1 [insert parent PID here]
You can also use this simple bash script to automate the removal of all zombie processes from your system at once.
#!/bin/bash
# Get a list of zombie processes
zombie_pids=$(ps aux | grep -w Z | awk '{print $2}')
# Iterate over zombie processes
for zombie_pid in $zombie_pids; do
# Get the parent PID of the zombie process
parent_pid=$(ps o ppid= -p $zombie_pid)
# Kill the parent process to reap the zombie
kill -1 $parent_pid
done
echo "Zombie processes removed."
Simply copy the above code to a new file, name it zombie_eliminator.sh, and then execute it using this command:
bash zombie_eliminator.sh
While proactive identification and elimination of zombie processes is important, preventing their occurrence altogether is even more crucial. Follow these best practices and guidelines to reduce the number of zombie processes in Linux:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t child_pid, wait_pid;
int status;
// Create a child process
child_pid = fork();
if (child_pid < 0) {
// Fork failed
perror("fork");
exit(EXIT_FAILURE);
} else if (child_pid == 0) {
// Child process
printf("Child process is running.\n");
sleep(2); // Simulate some work
exit(EXIT_SUCCESS); // Exit the child process
} else {
// Parent process
printf("Parent process is waiting for the child.\n");
// Wait for the child process to terminate
wait_pid = wait(&status);
if (wait_pid == -1) {
perror("wait");
exit(EXIT_FAILURE);
}
printf("Child process with PID %d has terminated.\n", wait_pid);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
// Signal handler function to reap zombie processes
void sigchld_handler(int signum) {
pid_t pid;
int status;
// Reap all zombie processes
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
printf("Parent process reaped child process with PID %d.\n", pid);
}
}
int main() {
pid_t child_pid;
struct sigaction sa;
// Register the signal handler for SIGCHLD
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
// Create a child process
child_pid = fork();
if (child_pid < 0) {
// Fork failed
perror("fork");
exit(EXIT_FAILURE);
} else if (child_pid == 0) {
// Child process
printf("Child process is running.\n");
sleep(2); // Simulate some work
exit(EXIT_SUCCESS); // Exit the child process
} else {
// Parent process
printf("Parent process is running and will continue to run.\n");
// Parent process continues running and will periodically reap
zombie processes
while (1) {
sleep(5); // Sleep for a while to allow child processes to terminate
printf("Parent process is still running.\n");
}
}
return 0;
}
If you save the above code into a file (say temp.c), compile it using gcc temp.c temp,and execute it using ./temp,you will notice that the parent program is able to reap the child process without terminating or encountering any issues.
Even with best practices in place, unexpected circumstances or bugs can still lead to the occasional zombie process. Therefore, regular monitoring is crucial to maintain a healthy, zombie-free Linux system.
With proactive and regular monitoring, you can identify and fix the root cause of the zombie problem before it can impact system performance or security. Moreover, you can unravel patterns that may indicate deep-seated problems within your applications or infrastructure.
Fortunately, there are several handy monitoring tools that you can use to monitor the health and performance of your Linux system, including vmstat, iostat,and sar.If you want a dedicated monitoring tool for zombie processes, you can check out the Zombie Process Monitoring plugin by Site24x7. The plugin provides real-time information about all the zombie processes in your Linux system.
Zombie processes may seem inconsequential at first, but if allowed to stack up, they can have serious repercussions for your Linux system. Follow the identification, troubleshooting, and prevention tips outlined in this guide to maintain a healthy, performant, and secure Linux environment, free from the clutches of the undead.
Write for Site24x7 is a special writing program that supports writers who create content for Site24x7 “Learn” portal. Get paid for your writing.
Apply Now