Begriff
Zombie Process
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Ein Prozess (Programm) ist fertig mit der Arbeit. Er stirbt (exit).
Normalerweise verschwindet er dann aus der Liste (top).
Manchmal bleibt er aber stehen, markiert als <defunct> oder Z.
Das ist ein Zombie.
Er verbraucht keine CPU und keinen Speicher. Er ist schon tot.
Er belegt nur noch einen Platz in der Prozesstabelle (eine Zeile).
Warum ist er noch da?
Weil sein "Eltern-Prozess" noch nicht seinen Totenschein abgeholt hat.
Merksatz: Ein bereits beendeter Prozess unter Linux/Unix, der noch in der Prozesstabelle steht, weil sein Elternprozess den Exit-Status noch nicht abgefragt hat.
Erkennen:
top oder ps aux | grep 'Z'.
Du siehst Status Z.
Töten:
Du kannst einen Zombie nicht töten (kill -9 bringt nichts). Er ist schon tot!
Du musst den Eltern-Prozess töten (oder reparieren).
Wenn der Vater stirbt, adoptiert der "Großvater" (Init, PID 1) die Zombies und räumt sie sofort auf.
1. Der Lifecycle (fork -> exit -> wait)
- Parent ruft
fork()-> Child entsteht. - Child arbeitet und ruft
exit(0). - Kernel gibt den Speicher des Child frei, aber behält die PID und den Exit-Code (0) im RAM. (Das ist der Zombie-Zustand).
- Parent muss
wait()oderwaitpid()aufrufen. ("Wie ist mein Kind gestorben?"). - Kernel liefert Exit-Code, und löscht den Zombie endgültig.
Bug: Wenn Parent vergisst,
wait()aufzurufen (schlecht programmiert), bleibt der Zombie ewig.
2. PID Exhaustion
Ein Zombie stört nicht die Performance.
Aber: Das OS hat nur begrenzt viele PIDs (Process IDs), oft 32768 (siehe /proc/sys/kernel/pid_max).
Wenn du 32.000 Zombies hast, können keine neuen Programme mehr starten. Server-Absturz.
3. Docker & Zombies (PID 1 Problem)
In einem Docker-Container läuft deine App oft als PID 1.
PID 1 hat in Linux die spezielle Pflicht, verwaiste Kinder zu adoptieren und aufzuräumen (Reaping).
Normale Apps (Java, Node.js) haben diese Logik nicht.
Wenn Prozesse im Container sterben, werden sie zu dauerhaften Zombies.
Lösung: Nutze tini (ein winziges Init-Programm) als Entrypoint (docker run --init). Tini spielt den Bestatter.
Der SIGCHLD Sturm und asynchrones Warten
Wenn ein Child-Prozess stirbt, schickt der Kernel passiv ein SIGCHLD-Signal an den Parent-Prozess: "Hey, eines deiner Kinder hat aufgegeben!"
Das Problem ist, wenn der Parent gerade schwer beschäftigt ist (Heavy I/O, Webserver-Requests buffern), ignoriert er das Signal oft versehentlich im Default-Zustand (SIG_DFL).
Der Kernel belässt das Kind als <defunct> Zombie, solange der Parent nicht aktiv zur Systemfunktion waitpid() greift, um den Exit-Memory wegzuräumen. Clevere Daemons verknüpfen den SIGCHLD Handler asynchron, rufen sofort ausladendes waitpid(-1, &status, WNOHANG) auf und räumen im Hintergrund den Loop auf, während ihr Haupt-Thread reibungslos das Netzwerk bespaßt, wodurch Zombies im Nanosekunden-Alter wieder abgeräumt werden.
Tini und das moderne Subreaper-Konzept (prctl)
Die traditionelle Linux-Regel besagte gnadenlos: Wenn der direkte Parent eines Zombies abstürzt (Orphan-Szenario), wird das verwaiste Kind brutal der PID 1 (Init-System wie systemd oder sysvinit) zugeworfen.
In containerisierten High-Tech Setups laufen oft komplexe CI/CD-Pipelines, wo Shell-Scripte wild Prozesse spawnen und dann grundlos krepieren.
Um nicht den Haupt-Daemon (PID 1) zu überfluten, ermöglicht Linux ab Kernel 3.4 Subreaping (prctl(PR_SET_CHILD_SUBREAPER)). Dies erlaubt jedem Programm (z.B. Docker's winzigem Side-Init tini), sich selbst für alle Prozesse in seiner Baum-Tiefe als "Ersatz-PID-1-Auffangstation" aufzuschalten. Verwaiste Kinder fallen nicht mehr ganz nach oben ins Root, sondern an den erstbesten Subreaper. Dieser räumt isoliert die <defunct> Kinder des Sub-Baums auf.
Der Strace-Debugger-Effekt
Häufige Panik-Meldung von Ops-Teams: "Warum ist mein aktiver Apache plötzlich ein Zombie?!"
Wenn ein Prozess aktiv geloggt wird, z.B. wenn man strace -p <PID> oder gdb ran hängt, setzt das OS den Prozess oft intern kurzfristig via "Trace Flag" auf Pausen. Die CPU des Kindes ruht.
Zombies sind nicht "aktiv laufend", aber was Ops beim Tracing oft nicht wissen: Wenn ein getracter Prozess per kill beendet wird, muss der Tracing-Debugger (pyspy, strace) den Prozess ebenfalls entkoppeln. Crast der Debugger während des Anhängens weg, bleibt der gestorbene Prozess permanent als Zombie eingeklemmt, weil der Kernel ihn künstlich als "Warte auf Debugger-Analyse" am Leben hält. Erst ein harter Cleanup des Tracers entfesselt diesen Geist in den Äther.
Quick-Check
Ist ein Zombie gefährlich?
Einzeln nein (verbraucht 0 Ressourcen). In Massen ja (PID-Verbrauch). Sie sind meist ein Symptom für schlechten Code im Eltern-Programm.Orphan vs. Zombie?
Orphan (Waise): Elternteil stirbt vor dem Kind. Das Kind wird von Init (PID 1) adoptiert und läuft weiter. Zombie: Kind stirbt vor dem Elternteil, aber Elternteil ignoriert den Tod.Sleeping Process?
StatusS. Das ist kein Zombie. Der Prozess lebt, wartet aber auf etwas (Netzwerk, Input). Völlig normal.