Programs that are poorly written or performing badly can leave zombie processes lurking inside your Linux computer. Find out how zombies are created, and how you can finally lay them to rest.
How Process States Work on Linux
Linux, of course, has to keep track of all the applications and daemons running on your computer. One of the ways it does this is by maintaining the process table. This is a list of structures in kernel memory. Each process has an entry in this list that contains some information about it.
There isn’t a great deal in each of the process table structures. They hold the process ID, a few other data items, and a pointer to the process control block (PCB) for that process.
It’s the PCB that holds the many details Linux needs to look up or set for each process. The PCB is also updated as a process is created, given processing time, and finally destroyed.
The Linux PCB contains over 95 fields. It’s defined as a structure called
task_struct.h, and it’s over 700 lines long. The PCB contains the following types of information:
- Process State: The states are described below.
- Process Number: Its unique identifier within the operating system.
- Program Counter: When this process is next given access to the CPU, the system will use this address to find the next instruction of the process that should be executed.
- Registers: The list of CPU registers used by this process. The list might contain accumulators, index registers, and stack pointers.
- Open File List: Files associated with this process.
- CPU Scheduling Information: Used to determine how frequently, and for how long, CPU processing time is awarded to this process. The priority of the process, pointers to scheduling queues, and other scheduling parameters have to be recorded in the PCB.
- Memory Management Information: Details about the memory this process is using, such as the start and end addresses of the process memory, and pointers to the memory pages.
- I/O Status Information: Any in- or output devices used by the process.
The “Process State” can be any of the following:
- R: A running or runnable process. Running meaning it’s receiving CPU cycles and executing. A runnable process is ready to run and waiting for a CPU slot.
- S: A sleeping process. The process is waiting for an action to complete, such as an in- or output operation, or for a resource to become available.
- D: The process is in an uninterruptible sleep state. It’s using a blocking system call and can’t continue until the system calls have completed. Unlike the “Sleep” state, a process in this state won’t respond to signals until the system call is completed and execution has returned to the process.
- T: The process has terminated (stopped) because it received the
SIGSTOPsignal. It will only respond to the
SIGCONTsignals, which either kill the process or instruct it to continue, respectively. This is what’s happening when you swap from foreground (
fg) to background (
- Z: A Zombie process. When a process completes, it doesn’t just vanish. It frees up any memory it’s using and removes itself from memory, but its entry in the process table and PCB remain. Its state is set to
EXIT_ZOMBIE, and its parent process is notified (by the
SIGCHLDsignal) that the child process has finished.
In the Zombie state, the parent process calls one of the
wait() families of functions when the child process is created. It then waits for a state change in the child process. Has the child process been stopped, continued, or killed by a signal? Has it terminated by running through the natural completion of its code?
If the state change is one that means the child process has stopped running, its exit code is read. Then, the child’s PCB is destroyed and its entry in the process table is removed. Ideally, this all happens in the blink of an eye, and processes in the zombie state don’t exist for very long.
What Causes Zombie Processes on Linux?
A poorly written parent process might not call the
wait() function when the child process is created. This means nothing is watching for state changes in the child process, and the
SIGCHLD signal will be ignored. Or, perhaps another application is affecting the execution of the parent process, either due to poor programming or malicious intent.
However, if the parent process isn’t watching for state changes in the child process, the proper system housekeeping won’t occur. The PCB and the entry in the process table won’t be removed when the child process terminates. This results in the zombie state never being removed from the PCB.
Zombies do use a bit of memory, but they don’t usually pose a problem. The entry in the process table is small, but, until it’s released, the process ID can’t be reused. On a 64-bit operating system, that’s unlikely to cause any issues because the PCB is much larger than the process table entry.
A huge number of zombies could, conceivably, affect the amount of memory that’s free for other processes. If you’ve got that many zombies, though, you’ve got a serious problem with the parent application or an operating system bug.
How to Remove Zombie Processes
You can’t kill a zombie process because it’s already dead. It won’t respond to any signals because it’s been removed from memory—there’s nowhere to send a
SIGKILL signal. You can try sending the
SIGCHLD signal to the parent process, but if it didn’t work when the child process terminated, it’s unlikely to work now, either.
The only reliable solution is to kill the parent process. When it’s terminated, its child processes are inherited by the
init process, which is the first process to run in a Linux system (its process ID is 1).
init process regularly performs the necessary cleanup of zombies, so to kill them, you just have to kill the process that created them. The
top command is a convenient way to see if you have any zombies.
Type the following:
Type the following:
ps aux | egrep "Z|defunct"
The zombie processes are listed.
This is a neater way to discover the process IDs of zombies than scrolling back and forth through
top. We also see that an application called “badprg” spawned these zombies.
The process ID of the first zombie is 7641, but we need to find the process ID of its parent process. We can do so by using
again. We’ll use the output option (
-o) to tell
ps to display only the parent’s process ID, and then pass it with the
The process we want to find will be indicated by using the
-p (process) option, and then passing in the zombie’s process ID.
Therefore, we type the following command to look up the process information for process 7641, but it will only report the ID of the parent process:
ps -o ppid= -p 7641
We’re told the parent process ID is 7636. We can now cross-reference this by using
ps once more.
We see this matches the name of the parent process from earlier. To kill the parent process, use the SIGKILL option with the kill command as follows:
kill -SIGKILL 7636
Depending on the owner of the parent process, you might also need to use
Zombies Aren’t Scary …
… unless they’re in a massive horde. A few aren’t anything to worry about and a simple reboot will wipe them out.
However, if you notice that an application or process is always spawning zombies, that’s something you should look into. It’s most likely just a sloppily written program, in which case, perhaps there’s an updated version that properly cleans up after its child processes.