Layer 8Ehrlicher Tech-Support

Linux: Zombie-Prozess überlebt kill -9, weil er schon tot ist

Ein Prozess mit Status Z lässt sich mit kill -9 nicht entfernen, auch nicht als root. Er ist längst beendet; abholen muss ihn sein Elternprozess.

Aufwand:
ca. 15 Min.
Voraussetzung:
Ein Terminal, ps aus procps-ng, kill als Shell-Builtin oder aus util-linux
Gilt für:
Linux (wait(2), kill(2) und signal(7) aus Linux man-pages 6.19; ps(1) aus procps-ng, Stand 23.04.2025; kill(1) aus util-linux 2.43)

Das Symptom

In ps oder top steht ein Prozess, der sich nicht verabschieden will. Die Zustandsspalte zeigt ein Z, hinter dem Namen steht <defunct>:

    PID    PPID STAT COMMAND
   4712    4711 Z    python3

Der Reflex ist bekannt: kill -9 auf die PID. Dann noch einmal. Dann mit sudo. kill beschwert sich nicht einmal, aber der Eintrag bleibt stehen, als wäre nichts gewesen. Spätestens jetzt wächst der Verdacht, der Prozess hänge irgendwo im Kernel fest, fresse heimlich Speicher oder das System sei grundsätzlich kaputt, und der Neustart des ganzen Servers rückt näher.

Die „Layer 8“-Wahrheit

Das Missverständnis steckt im Wort. Ein Zombie ist kein Untoter, der sich gegen Signale wehrt, sondern ein Toter, der noch nicht abgeholt wurde. wait(2) beschreibt den Zustand nüchtern: Ein Kindprozess, der sich beendet hat, auf den aber noch kein wait ausgeführt wurde, wird zum Zombie. „The kernel maintains a minimal set of information about the zombie process (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child.“ ps(1) sagt es in einer Zeile: „terminated but not reaped by its parent“.

Damit ist auch klar, warum kill nichts ausrichtet. SIGKILL beendet einen laufenden Prozess; dieser hier läuft nicht mehr. kill(2) behandelt ihn trotzdem als existierend und hält bei ESRCH ausdrücklich fest, dass ein existierender Prozess „might be a zombie, a process that has terminated execution“. Deshalb kommt nicht einmal eine Fehlermeldung. Das Signal wird angenommen, und es passiert genau nichts, weil niemand mehr da ist, der es ausführen könnte.

Der Schlüssel liegt eine Ebene höher, beim Elternprozess. Holt er den Status mit wait ab, verschwindet der Zombie. Beendet er sich, übernimmt init die Waisen: „init(1) automatically performs a wait to remove the zombies.“ Wer also aufräumen will, schaut auf die PPID statt auf die PID und kümmert sich um das Programm, das seine Kinder liegen lässt. Auch ein Neustart des ganzen Servers beseitigt die Zombies nur deshalb, weil er nebenbei ihren Elternprozess beendet, und alles andere gleich mit. Denselben Effekt hat ein gezielter Neustart des einen Programms.

Harmlos im Sinne von egal sind Zombies trotzdem nicht. Solange kein wait erfolgt, belegt jeder einen Platz in der Prozesstabelle, und wait(2) warnt, dass sich bei voller Tabelle keine neuen Prozesse mehr starten lassen. Ein einzelner Zombie ist eine Kuriosität. Eine wachsende Zahl unter demselben Elternprozess ist ein Programmierfehler, und der wird weder durch kill -9 noch durch mehr Geduld behoben, sondern im Code des Elternprogramms.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Zombies samt Elternprozess auflisten

    ps mit eigenem Ausgabeformat zeigt für jeden Prozess PID, Eltern-PID, Zustand und Befehlsnamen. Laut ps(1) steht Z im Zustand für einen beendeten, aber vom Elternprozess nicht abgeholten Prozess. Der awk-Filter behält nur die Zeilen, deren dritte Spalte mit Z beginnt. Wichtig ist die zweite Spalte, die PPID: Sie zeigt, wer für das Aufräumen zuständig wäre und es offenbar nicht tut.

    ps -e -o pid,ppid,stat,comm | awk '$3 ~ /^Z/'
    
  2. 2.

    Akzeptieren, dass kill auf den Zombie nichts ändert

    Ein weiteres kill auf die PID des Zombies kostet nur Zeit. Der Prozess hat seine Ausführung beendet; was bleibt, ist ein Statuseintrag für den Elternprozess. Bei einem Test für diesen Eintrag meldete kill -9 auf einen Zombie sogar Erfolg mit Rückgabewert 0, und der Eintrag blieb trotzdem stehen. Das passt zu kill(2), das einen Zombie noch als existierenden Prozess behandelt. Erfolg heißt hier nur: Signal zugestellt, Empfänger tot.

  3. 3.

    Den Elternprozess ansehen

    Mit der PPID aus dem ersten Schritt lässt sich der Elternprozess gezielt anzeigen, hier mit Zustand, Laufzeit seit dem Start und Befehlsnamen. Die Zahl 4711 ist ein Platzhalter für die echte PPID. Steht als PPID die 1, ist der Zombie bereits bei init gelandet, das ihn laut wait(2) automatisch abräumt. Interessant ist der Fall, in dem ein lange laufender Dienst oder ein eigenes Skript als Eltern auftaucht.

    ps -o pid,stat,etime,comm -p 4711
    
  4. 4.

    Den Elternprozess an seine Pflicht erinnern

    Manche Programme holen beendete Kinder in einem Handler für SIGCHLD ab. Ein von Hand geschicktes SIGCHLD kann sie dazu bringen, das nachzuholen. Ob das wirkt, hängt allein vom Programm ab. Hat es keinen eigenen Handler, passiert nichts, denn die Standardreaktion auf SIGCHLD ist laut signal(7) Ignorieren. Der Versuch ist also ungefährlich, aber keine Garantie.

    kill -s CHLD 4711
    
  5. 5.

    Den Elternprozess beenden oder sauber neu starten

    Hilft das nicht, bleibt der Elternprozess selbst. Ohne Angabe schickt kill laut kill(1) das Signal TERM, das dem Programm Gelegenheit zum geordneten Beenden gibt. Danach übernimmt init die Zombies und räumt sie ab. Vorher prüfen, was da beendet wird: Ist der Elternprozess ein Dienst, ist ein Neustart über die Dienstverwaltung der sauberere Weg. Häufen sich Zombies unter demselben Programm immer wieder, ist das ein Fehler in diesem Programm.

    kill 4711
    

Häufige Fragen (FAQ)

?Warum wirkt kill -9 auf einen Zombie nicht?

Weil es nichts mehr zu beenden gibt. Ein Zombie ist laut wait(2) ein Kindprozess, der sich bereits beendet hat, auf den aber noch kein wait ausgeführt wurde. Übrig ist nur ein Eintrag mit PID, Beendigungsstatus und Ressourcenverbrauch, den der Elternprozess abholen soll. kill(2) zählt so einen Zombie ausdrücklich noch als existierenden Prozess, „a process that has terminated execution“. Das Signal geht also nicht ins Leere, es trifft nur niemanden mehr, der es ausführen könnte.

?Verbraucht ein Zombie Speicher oder Rechenzeit?

Rechenzeit nicht, denn er läuft nicht mehr. Der Kernel hält laut wait(2) nur eine minimale Menge an Informationen über ihn fest: PID, Beendigungsstatus und Angaben zum Ressourcenverbrauch. Ganz kostenlos ist er trotzdem nicht. Solange kein wait erfolgt, belegt er einen Platz in der Prozesstabelle des Kernels, und wait(2) warnt: Ist diese Tabelle voll, lassen sich keine weiteren Prozesse mehr erzeugen. Ein einzelner Zombie ist also harmlos, Tausende vom selben Elternprozess sind es nicht.

?Wie werde ich einen Zombie dann los?

Über seinen Elternprozess. Entweder holt der Elternprozess den Status mit wait ab, oder er beendet sich selbst. Für den zweiten Fall beschreibt wait(2), was passiert: Die Zombie-Kinder werden von init(1) übernommen, oder vom nächsten mit prctl(2) eingerichteten Subreaper, und init führt automatisch ein wait aus, das die Zombies entfernt. ps(1) sagt dasselbe kürzer: Solche Prozesse werden von init beseitigt, wenn der Elternprozess endet. Der Hebel ist also immer die PPID, nie die PID des Zombies.

?Ist ein Prozess, der einen Port blockiert, ein Zombie?

Nein. Umgangssprachlich wird mancher Prozess, der irgendwo übrig geblieben ist, Zombie genannt. Im Sinne von wait(2) und ps(1) ist ein Zombie aber ein Prozess, der seine Ausführung bereits beendet hat und nur noch auf das Abholen seines Status wartet; ps zeigt ihn mit dem Zustand Z. Ein Prozess, der noch einen Port belegt oder sonst etwas tut, läuft dagegen und reagiert auf Signale wie jeder andere lebende Prozess. Für ihn ist kill das richtige Werkzeug, für einen echten Zombie nicht.

?Ich entwickle das Programm, das die Zombies erzeugt. Was mache ich falsch?

Das Programm startet Kindprozesse und holt deren Beendigungsstatus nicht mit wait oder waitpid ab. Genau das verlangt wait(2), damit der Kernel den Eintrag freigeben kann. Wer am Status der Kinder kein Interesse hat, kann laut wait(2) die Behandlung von SIGCHLD ausdrücklich auf SIG_IGN setzen oder das Flag SA_NOCLDWAIT verwenden; dann werden beendete Kinder gar nicht erst zu Zombies. Die Handbuchseite betont, dass das ausdrückliche Setzen von SIG_IGN anders wirkt als die Standardbehandlung, obwohl beide ignorieren.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

OSLästigArgument list too long

bash: Argument list too long

Der Befehl bricht mit 'Argument list too long' ab, weil ein * zu viele Dateien liefert. So löst du es mit find und xargs statt Globbing.