Claude on Question 13, Sep 23
How do I kill a zombie process in Linux that won't respond to SIGTERM?The short answer: you can't kill a zombie
A zombie (state Z, sometimes shown as defunct) is already dead. It has exited, released its memory, closed its file descriptors — all that remains is an entry in the process table holding its exit status, waiting for its parent to call wait()/waitpid() to collect it.
Since there's no running code, signals have nowhere to go. SIGTERM, SIGKILL, kill -9 — all ignored, by design.
The fix is always to deal with the parent.
Find the zombies and their parents
ps -eo pid,ppid,stat,comm | awk '$3 ~ /^Z/'
Or a quick count:
ps -eo stat | grep -c '^Z'
Step 1: Nudge the parent with SIGCHLD
The parent is supposed to reap on SIGCHLD. If it has a handler but missed the notification, re-sending it can work:
kill -s SIGCHLD <PPID>
This is harmless and worth trying first. It often does nothing, though, because the usual cause is a parent that never reaps at all.
Step 2: Restart or kill the parent
When the parent dies, its zombie children are re-parented to PID 1 (init/systemd), which reaps them immediately.
# Graceful first kill <PPID> # Or for a service systemctl restart <service>
If the parent is a service you can't restart casually, SIGKILL on the parent works too, but you'll lose any in-flight work.
Step 3: Figure out why the parent is stuck
If the parent isn't reaping, it's either buggy or blocked. Check:
cat /proc/<PPID>/status | grep -i state cat /proc/<PPID>/wchan # what kernel function it's sleeping in sudo strace -p <PPID> # is it doing anything?
A parent in state D (uninterruptible sleep) is typically stuck on I/O — a hung NFS mount, a failing disk, a dead network filesystem. That's the real problem; the zombies are just a symptom, and the parent won't respond to SIGKILL either until the I/O resolves.
Do you even need to act?
A zombie costs a process-table slot and a PID. A handful is cosmetic noise. It only becomes a real problem when they accumulate toward:
cat /proc/sys/kernel/pid_max # usually 32768 or 4194304
Exhausting that means nothing on the system can fork — that's when you get "cannot allocate memory" or "fork: retry" errors.
Preventing it in your own code
C: either reap explicitly, or tell the kernel you don't care:
signal(SIGCHLD, SIG_IGN); // kernel auto-reaps, no zombies ever
…or handle it properly:
void reaper(int sig) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
signal(SIGCHLD, reaper);The while loop matters — signals coalesce, so one SIGCHLD may represent several exits.
Python: always .wait() or .communicate() on subprocess.Popen objects. Fire-and-forget Popen calls are the classic zombie factory.
Shell: wait after backgrounding jobs.
Containers: this bites people constantly. If your app runs as PID 1 in Docker, it inherits orphans but usually has no reaping logic. Fix with:
docker run --init ...
or add tini/dumb-init as your entrypoint. In Kubernetes, set shareProcessNamespace: true or just use a proper init in the image.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-23 09:06:16 UTC
- Run
- 20260923T090022Z-9b7b3a
- Served by
- Claude Platform on AWS · HTTP 200 · finish stop
- Size
- 3,181 characters · 1,896 tokens out incl. hidden reasoning · 26.3 s
End of response · 96 lines · 3,181 characters · sha256 5ccebb8d945efa2edff8bc1e309e68556f1b00cca57c5b1c898cf9e94dd83672