- A zombie process is a terminated child process that remains in the process table because its parent has not called wait().
- They are detected with commands such as ps and top, where they appear with a Z status or labeled as .
- They don't consume CPU, but many zombies can fill up the process table and cause serious problems.
- Proper cleanup involves forcing the parent process to collect the child's state, using signals such as SIGHUP or SIGCHLD.
In the world of GNU/Linux and other UNIX systems, talking about zombie processes It has nothing to do with TV series or horror movies, even though the name is quite fitting. It refers to those half-dead, half-alive processes that linger in the process table and, if they accumulate, can cause more than a few headaches for the system administrator.
It is important to understand what they are, how they are created, and how detect zombie processes in Linux (and in MacOSand, above all, how to remove them without damaging anything important. Below you will find a detailed explanation, combining system theory, practical examples with commands such as ps o top, several methods to kill these dead processes and even a small C program to generate a test zombie.
What exactly is a zombie process in Linux?
A zombie (or defunct) process It is a child process that has already finished executing, but still retains an entry in the system's process table. This entry remains so that its parent process can query the child's exit code using calls such as wait() o waitpid()Until the father makes that reading, the son does not completely disappear.
From a metaphorical point of view, the son has died, but his “soul” is still registered in the system. That's why they're called zombies or dead processes: they're no longer executing code, they don't consume CPU or user memory, but they do occupy a small space in the process table. If there are one or two, it's not a problem, but if a poorly programmed application generates many, we can run into problems.
In Unix and Linux systems, when a process terminates, the kernel releases its resources (memory, file descriptors, etc.), but retains that minimal record with the exit state. If the parent never calls wait()That record isn't cleared, and the process remains marked as zombie. In other words, it's almost always a programming problem or the design of the software that acts as the parent process.
These processes are easily recognized because in tools such as ps appear with the status Z (of zombie) or with the label and on monitors like top There are specific counters that show how many zombies we have active in the system at any given time.

Process states in Linux
To understand the role of zombies, it's helpful to review the process states more common in Linux. When we list processes with ps o topA letter is used to indicate the state:
- Sleeping: processes sleeping, waiting for their turn to execute or for some event to occur.
- Running(R): processes that are running on CPU or ready to run.
- Waiting(D): blocked processes waiting for the completion of an input/output operation (uninterruptible wait).
- Stopped (T): processes stopped, for example, by signals such as SIGSTOP or because they are in debug mode.
- Zombie (Z): processes that have finished, but continue to appear in the process table waiting for their parent to read their exit status.
Each line of ps It displays a process with its PID, PPID (parent PID), user, status, and other data. The status field can be called S, STAT or similar, according to the parameters of ps. A process with state Z It is, officially, a zombie. In many cases, the command or process name will be displayed as which makes it clear that he is deceased.
How to detect zombie processes in Linux from the terminal
The most direct way to locate zombie processes is to use classic monitoring commands: ps y topCombine them with tools such as grep, awk o xargs It allows filtering and preparing lists of PIDs with considerable accuracy.
One of the most used commands to see zombies is:
ps -el | grep 'Z'
Parameter -he This causes PS to display an extended output, where the second column typically indicates the process status. In that column, we can find, among other things:
- S: sleeping.
- R: running.
- D: waiting (uninterrupted wait).
- T: stopped or gestopt (suspended).
- Z: zombie (defunct).
For a more detailed example, on a machine with problematic processes we might get something like:
ps -el | grep 'Z'
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
1 Z 0 1213 589 0 75 0 – 0 funct> ? 00:00:00 dovecot-auth
Here we see that the process dovecot-auth It's marked with status Z, so it's a zombie. Also, look at the column. PPIDbecause that is the PID of the parent process that we will talk about later in order to properly clean up the zombie.
Another very common way to list zombies is to use the combination:
ps -A -ostat,ppid,pid,cmd | grep -e '^'
In this case, with -A We list all the processes and the option -o It allows us to define exactly the columns we want: status (stat), PPID, PID, and the command. The filter grep -e '^' It only keeps the lines whose state begins with Z oz, that is, zombie processes.
Another, somewhat more minimalist, option would be:
ps axo pid=,stat= | awk '$2~/^Z/ { print $1 }'
In this version, we only ask for the PID and the status, without headers (with pid=,stat=), and then with awk We filter the rows whose state field begins with Z, printing only the PID of the zombie process. This is an elegant way to generate a list of zombie PIDs for later use. kill or with other pipes.

Using top to locate zombie processes
The command top It's a very convenient interactive tool for seeing in real time what's happening in the system. At the top of top A summary is displayed showing the total number of tasks and how many are in each state, including how many zombies There are assets at that time.
To use it, simply run:
top
In the first or second line you will see something like this: Tasks: 150 total, 1 running, 149 sleeping, 0 stopped, 1 zombieThat zombie counter already tells you if there are dead processes hanging off the system. Furthermore, when scrolling down the process list, in the column S (state) you will be able to easily locate those marked with a Z.
One limitation of `top` is that, although it indicates how many zombies there are, it's not always as convenient as `ps` for extracting only those processes. That's why it's very common to combine them: first, you check with `top` if there are zombies, and then you use `ps`. ps with the filters we have seen to identify them in detail and prepare the commands that will eliminate them.
Some articles also suggest another specific command to view defunct processes with more information:
ps axo stat,ppid,pid,comm | grep -w defunct
This command focuses on processes whose command is marked as defunct; again you will see the status, the parent PID, the child PID and the associated command, which makes it much easier to trace the problem back to the parent process.

What happens in the kernel with a zombie process
At the internal level of the Linux kernel, each process is represented by a data structure called struct task_structWithin that structure there are fields that indicate the state of the process, including exit_state, which is where the exit state is stored when the process ends.
When a process terminates, the kernel marks that process with a value such as EXIT_ZOMBIE (defined in the kernel headers) within that field exit_stateThis means the process has already finished, but it's still waiting for the parent program to collect the output information. As long as the parent program hasn't executed wait()The kernel does not change that state nor completely remove the entry from the process table.
The interesting detail is that, although a zombie doesn't consume significant CPU or working memory, it does occupies a slot in the process tableAnd that table has a finite size. If an application is creating child processes in a loop that are never cleaned up (because the parent doesn't call wait()), we could end up with hundreds or thousands of zombies, exhausting the table's capacity and causing failures when creating new processes.
How to terminate zombie processes in Linux
Once we've detected zombie processes, we need to think about how to effectively "kill" them. Here's a key point: The zombie process is already dead.in the sense that it is not running. Therefore, sending signals like SIGKILL (kill -9) directly to the zombie is useless; there is no code to heed that signal.
What really needs to be done is to get the parent process reads the exit state of the childThis can be achieved in several ways: by sending appropriate signals to the parent, by forcing the parent to terminate (so that init or systemd adopt the zombie and clean it up), or by using combinations of commands that automate that task.
First option: send SIGHUP to the parent
A very common solution is to find the PPID of zombie processes and send a signal to the parent to execute wait() and collect the states of its children. A typical command is:
kill -HUP `ps -A -ostat,ppid,pid,cmd | grep -e '^' | awk '{print $2}'`
Here's what happens: first, all processes are listed with their status, PPID, PID, and command; then, those whose status starts with Z are filtered; finally, with awk '{print $ 2}' The second column is extracted, which is the PPID (the parent process identifier). That list of parent PIDs is passed to kill -HUP, which sends the signal FOLLOW UP to each other.
In many applications, this signal causes the parent process to reload its configuration or perform some cleanup. In this context, the idea is for the parent to do a wait() appropriate and get rid of the zombiesIt's a rather aggressive but practical method, especially when there are many zombies accumulated and it's known that they share the same parent process.
Second option: use SIGCHLD
Another approach involves sending the signal SIGCHLD to the problematic parent process. This signal tells a process that one of its children has changed state (for example, terminated). Normally, when a child process dies, the kernel sends SIGCHLD to the parent; if the parent has a signal handler configured, it usually calls wait() within that handler.
If you detect that several zombies have the same PPID, you can try:
kill -s SIGCHLD
For example:
kill -s SIGCHLD 2201
With this you are remembering the father which has dead children pending. If the parent process is well programmed to react to SIGCHLD, it will clean up its zombies using wait(). This method is less abrupt than terminating the parent and, if the program is well written, is the most natural way to resolve the problem.
Third option: kill the parent process
If the parent process is blocked, unresponsive to signals like SIGHUP or SIGCHLD, or clearly hung, another option is to terminate it forcefully. In this case, the classic method is used:
kill -9
For example:
kill-9 2201
By doing this, the kernel terminates the parent process. In most modern systems, systemd or the process init They adopt the orphans (including zombies) and are responsible for calling wait() on them, thus clean your entrance in the process table. It's not the most elegant way, but sometimes it's the only way to get rid of a collection of zombies originating from a faulty program.
Other advanced combinations with ps, awk and kill
In addition to the examples above, there are many one-liners that automate the search for zombies and the sending of signals to their parent processes. Some representative examples are:
ps axo state,pid | awk '$1==»2″ {print $2}' | xargs kill -s SIGKILL
This command selects processes based on the numerical value of their status; however, it is used less frequently because it is less readable than working with the letter Z. Other common commands for dealing with zombies are:
ps -xaw -o state,ppid | grep Z | grep -v PID | awk '{ print $2 }' | xargs kill -9
O well:
kill -9 `ps xawo state=,pid= | sed -n 's/Z //p'`
or even:
kill -9 `ps -xaw -o state -o ppid | grep Z | grep -v PID | awk '{print $2}'`
In all cases, the idea is similar: locate processes with state Z, extract their PIDs or the corresponding PPIDs and apply kill with the signal we deem appropriate (SIGHUP, SIGCHLD, SIGKILL, etc.). However, these recipes must be used with some caution, because kill important parent processes Without thinking twice, it can leave services down or the system unstable.
Practical example: creating a zombie process with C
To be able to run tests without damaging anything, a classic technique is create a zombie process in a controlled manner with a small program in C. This way we can see exactly how it appears in ps, how it is marked as and practice the commands to remove it.
A very simple program that generates a zombie could be this:
#include
#include
#include
int main ()
{
pid_t child_pid;
child_pid = fork();
if (child_pid > 0) {
sleep (60);
}
else {
exit (0);
}
0 return;
}
In this code, the parent process does a fork ()The son immediately ends with exit (0)while the father stays sleeping 60 secondsDuring that time, the son is dead but the father has not yet called wait()so the child remains in a zombie state in the process table.
To compile this program you can use gcc as follows:
gcc -o zombie1 zombie.c
And to run it in the background, simply:
./zombie1 &
While the father is still asleep, you can execute ps -el | grep 'Z' or any of the commands above, and you'll see your zombie process in action. After a few seconds, when the parent process finishes and the system cleans up, the zombie will disappear.
Impact of zombie processes and common causes
A single, isolated zombie process, It's not usually a cause for concern.It doesn't consume CPU, the memory associated with the process has already been freed, and the direct impact on performance is minimal. The problem arises when many zombie processes accumulate, usually because the software is poorly designed or has bugs in its child process management.
The most frequent causes of zombies are:
- Poor programmingThe parent process creates child processes but does not correctly implement SIGCHLD management or call wait() or waitpid() to collect the state of the children.
- Configuration errorsSome services may create child processes in a loop under certain configurations not foreseen by the developer, generating a cascade of zombies.
- Parent process crashes or freezesIf the parent gets stuck in an I/O operation or in an infinite loop, it can leave dead children uncleaned up.
When there are many zombie processes, the process table can to be filled with dead entriesmaking it difficult to create new processes and generating symptoms such as slowness, errors when launching applications, or strange behavior in critical services (for example, web servers like Apache generating hundreds of defunct processes).
Therefore, it is important to check with [sometimes/from time to time] top o ps If there are zombies, especially on production servers, it's crucial to correct the root cause: update the problematic software, fix the code that manages child processes, or adjust configurations that are causing the uncontrolled creation of child processes.
Graphical alternatives for desktop users
If you're not comfortable using the terminal or simply prefer a visual solution, many Linux graphical environments allow you to use the command prompt. System Monitor (System Monitor) or equivalent tools that offer a graphical view of the processes.
The general procedure would be something like this:
- Open the app System Monitor from your desktop menu.
- Go to the tab Processes, where all active processes are listed.
- Use the search tool (usually a magnifying glass icon) to search for terms like zombie or look at the status column to locate processes marked as or Z.
- Select the problematic process, right-click, and choose the option to "Kill" or “End process”.
For this to work correctly, it's key to make sure the monitor is displaying all system processes And not just those of the current user. There's usually a checkbox or option in the settings that allows you to "Show processes from all users" or something similar.
Good practices to prevent the proliferation of zombies
Beyond the tricks for killing zombies once they've appeared, it's worth applying some good practice to minimize the occurrence of these processes in production systems.
Among the most important recommendations are:
- Keep the system and software up to dateOften, zombie processes come from bugs that have already been fixed in later versions of a server or application.
- Review the scheduling of child processesIf you develop software that uses fork(), make sure you handle SIGCHLD correctly and call wait() or waitpid() for each child that terminates.
- Monitor periodicallyIncorporating commands like ps -el, ps axo stat,ppid,pid,comm or top into monitoring scripts or observability tools helps to immediately detect zombie spikes.
- Investigate the origin when recurring zombies appearIf they are always children of a specific service (for example, a mail server or a specific daemon), it may be necessary to review its configuration or version.
On occasion, even specific scripts have been published (for example, called zombie.shThese processes automate all of this logic: they locate zombie processes, identify their parent processes, send the appropriate signals, and attempt to clean up the process table. They are useful as a last resort when manual methods fail, but it's always important to know what they are doing behind the scenes to avoid surprises.
Ultimately, understanding what a zombie process is, how to view it with ps y tophow signals work FOLLOW UP, SIGCHLD y SIGKILL about the parent processes and what programming patterns lead to this state allows you to diagnose and solve with ease virtually any problem related to dead processes in Linux, keeping your systems cleaner, more stable, and with the process table under control.
Passionate writer about the world of bytes and technology in general. I love sharing my knowledge through writing, and that's what I'll do on this blog, show you all the most interesting things about gadgets, software, hardware, tech trends, and more. My goal is to help you navigate the digital world in a simple and entertaining way.