kill -9 sur un PID en état Z (zombie) dans ps aux ne fait rien, le processus reste zombie. Ce n’est pas un bug de kill : un processus zombie est déjà mort, il ne reste qu’une entrée dans la table des processus du kernel, et on ne tue pas ce qui est déjà mort.

Ce qu’un zombie est réellement

Quand un processus se termine, le kernel conserve son code de sortie dans la table des processus jusqu’à ce que le processus parent le récupère via un appel système wait() ou waitpid(). Entre la fin réelle du processus et cette récupération, l’entrée existe encore mais ne consomme plus de mémoire ni de CPU : c’est l’état zombie (Z), une transition normale et attendue, pas une anomalie en soi.

# État Z = zombie, déjà terminé,
# en attente que son parent récupère son code de sortie
ps aux | grep ' Z '
#  user  1234  0.0  0.0      0     0 ?  Z  10:03  0:00 [my-worker] <defunct>

Pourquoi le problème n’est jamais l’enfant

Un zombie isolé, en transit le temps que le parent traite l’événement SIGCHLD, se résorbe seul en quelques instants. Le vrai problème apparaît quand un parent ne récupère jamais ses enfants terminés, souvent un bug applicatif (boucle de fork sans wait() correspondant, ou gestion d’erreur qui saute l’appel de récupération) : les zombies s’accumulent indéfiniment, chacun occupant une entrée dans la table des processus jusqu’à épuisement possible du nombre de PID disponibles sur la machine.

# Compte les zombies : un accumul continu pointe
# vers un bug de récupération dans le parent, pas dans l'enfant
ps -eo stat | grep -c '^Z'

Le vrai correctif : réparer ou redémarrer le parent

Puisqu’un zombie ne peut pas être tué, la correction agit toujours sur le parent : soit corriger son code pour qu’il appelle wait()/waitpid() sur ses enfants terminés, soit le redémarrer purement et simplement. Un redémarrage du parent libère automatiquement tous les zombies qu’il n’avait pas récupérés : à la mort du parent, ses enfants zombies sont réattribués (« reparentés ») à init (PID 1, ou systemd sur la plupart des distributions modernes), qui les récupère automatiquement et immédiatement. Ce mécanisme de réparentage est le même qui garantit qu’un service géré par systemd ne laisse jamais de zombies orphelins traîner indéfiniment sur le système.

À retenir

Un processus zombie est déjà mort, SIGKILL ne peut rien faire de plus contre lui : seule une entrée dans la table des processus attend d’être récupérée par son parent via wait(). Une accumulation continue de zombies pointe systématiquement vers un bug de récupération dans le code du parent, jamais dans l’enfant terminé. Redémarrer (ou corriger) le parent est le seul correctif réel, le réparentage automatique vers PID 1 se chargeant ensuite de récupérer proprement tout ce qui restait en suspens.