Comme un véritable zombie, un processus zombie ne peut pas être tué, car il est déjà mort.
Comment ça se passe
Lorsque sous Linux / Unix un processus meurt / se termine, toutes les informations du processus sont supprimées de la mémoire système, seul le descripteur de processus reste. Le processus passe à l'état Z (zombie). Son processus parent reçoit un signal du noyau: SIGCHLD
cela signifie que l'un de ses enfants traite les sorties, est interrompu ou reprend après avoir été interrompu (dans notre cas, il se termine simplement).
Le processus parent doit maintenant exécuter l' wait()
appel système pour lire l'état de sortie et d'autres informations de son processus enfant. Ensuite, le descripteur est supprimé de la mémoire et le processus n'est plus un zombie.
Si le processus parent n'appelle jamais l'appel wait()
système, le descripteur de processus zombie reste en mémoire et mange le cerveau. Normalement, vous ne voyez pas les processus zombies, car la procédure ci-dessus prend moins de temps.
L'aube des morts
Chaque descripteur de processus a besoin d'une très petite quantité de mémoire, donc quelques zombies ne sont pas très dangereux (comme dans la vraie vie). Un problème est que chaque processus zombie conserve son identifiant de processus, et un système d'exploitation Linux / Unix a un nombre limité de pid. Si un logiciel mal programmé génère beaucoup de processus zombies, il peut arriver que les processus ne puissent plus être démarrés car il n'y a plus d'ID de processus disponibles.
Donc, s'ils sont en groupes énormes, ils sont très dangereux (comme dans de nombreux films, cela est très bien démontré)
Comment se défendre contre une horde de zombies?
Un coup dans la tête fonctionnerait, mais je ne connais pas la commande pour cela (SIGKILL ne fonctionnera pas car le processus est déjà mort).
Eh bien, vous pouvez envoyer SIGCHLD via kill au processus parent, mais quand il ignore ce signal, alors quoi? Votre seule option est de tuer le processus parent et que le processus init "adopte" le zombie. Init appelle périodiquement le wait()
syscall pour nettoyer ses enfants zombies.
Dans ton cas
Dans votre cas, vous devez envoyer SIGCHLD au processus crond:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
Puis depuis un autre terminal:
root@host:~$ kill -17 $(pgrep cron)
La sortie est:
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fff51be39dc, WNOHANG, NULL) = -1 ECHILD (No child processes) <-- Here it happens
rt_sigreturn(0xffffffffffffffff) = -1 EINTR (Interrupted system call)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x403170, [CHLD], SA_RESTORER|SA_RESTART, 0x7fd6a7e9d4a0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({42, 0}, ^C <unfinished ...>
Process 1180 detached
Vous voyez le wait4()
syscall renvoie -1 ECHILD, ce qui signifie qu'aucun processus enfant n'est là. La conclusion est donc: cron réagit au syscall SIGCHLD et ne doit pas forcer l'apocalypse.