top shows 1 zombie, or ps lists processes marked <defunct> with state Z. Zombies sound alarming, but a few are usually harmless. Here’s what they are, when they matter, and how to get rid of them. Hint: kill -9 on the zombie won’t work.

What a zombie is

When a process exits, it doesn’t vanish immediately. The kernel keeps a tiny entry (PID, exit status, resource usage) until the parent process reads that exit status with wait(). This is called reaping. Between exiting and being reaped, the process is a zombie.

A zombie:

  • uses no CPU and no memory beyond its process table entry;
  • can’t be killed, because it’s already dead;
  • disappears when its parent reaps it, or when the parent itself exits.

Short-lived zombies are normal. Persistent zombies mean the parent program has a bug: it starts children and never waits for them.

Find zombies

top                                     # "zombie" count in the Tasks line
ps aux | awk '$8 ~ /^Z/'                # STAT column starts with Z
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/'
  PID  PPID STAT CMD
 4821  4410 Z    [php] <defunct>
 4822  4410 Z    [php] <defunct>

The PPID column is the important one. It identifies the parent that isn’t reaping.

ps -o pid,user,cmd -p 4410

When do they matter?

  • A handful: cosmetic. Monitoring may complain, but there’s no resource impact.
  • Thousands and growing: each zombie holds a PID. If the system reaches the PID limit (/proc/sys/kernel/pid_max), or a cgroup’s TasksMax, new processes can’t start. Fork failures follow: “Resource temporarily unavailable”.
ps -eo stat | grep -c '^Z'
cat /proc/sys/kernel/pid_max

How to clear them

You can’t kill a zombie. You deal with its parent.

1. Ask the parent to reap. Some programs reap on SIGCHLD:

kill -s SIGCHLD 4410

This often does nothing with buggy parents, but it’s harmless to try.

2. Restart the parent. When the parent exits, its zombies are re-parented to PID 1 (systemd), which reaps them immediately:

sudo systemctl restart myapp          # if the parent is a service
kill 4410                             # or terminate the parent process

This is the reliable fix. Plan it for a quiet moment if the parent is an important service.

3. If the parent is PID 1 (systemd) and zombies persist, something is unusual. Check journalctl for errors. Inside a container, see below.

Prevent zombies

In your own code

Always wait for child processes:

  • Python: use subprocess.run() (it waits), or call .wait() / .communicate() on Popen objects.
  • Node.js: child_process handles reaping. Make sure you handle exit and close events, and don’t leak spawned processes.
  • Bash: background jobs started with & are reaped by the shell. Use wait in long-running scripts that spawn many jobs.
  • C/Go and others: handle SIGCHLD or call waitpid().

In Docker containers

This is a very common source of zombies. Your app runs as PID 1 in the container. If it spawns child processes (shell scripts, PhantomJS/Chrome, git, ImageMagick) and doesn’t reap them, zombies pile up, because PID 1 normally reaps orphans and your app doesn’t know it has to.

Fix it with a minimal init process:

docker run --init myimage
# docker-compose.yml
services:
  app:
    image: myimage
    init: true

Or include tini or dumb-init as the entrypoint in your Dockerfile:

RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]

The init also forwards signals properly. See Linux signals and Dockerfile tutorial.

Zombie vs orphan vs stuck (D state)

State Meaning Fix
Z (zombie) Dead, waiting to be reaped Restart or fix the parent
Orphan Running, parent died, adopted by PID 1 Usually fine. Stop it if unwanted
D (uninterruptible sleep) Alive, stuck waiting on I/O (disk, NFS) Fix the I/O issue. Can’t be killed while in D

D-state processes raise the load average without using CPU. See load average.

Quick reference

Task Command
Count zombies ps -eo stat | grep -c '^Z'
List with parent ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/'
Show parent ps -o pid,cmd -p PPID
Nudge parent kill -s SIGCHLD PPID
Real fix Restart the parent / fix its code
Docker --init or init: true

Related: ps command and kill a process.

  • Linux
  • Processes
  • Troubleshooting