Procesos zombie en Linux; qué son y cómo "matarlos"

Publicado el 22 noviembre 2016 por Drassill
Cualquiera que haya tratado con terminales Linux con cierta regularidad, se ha encontrado alguna vez en su vida con procesos "especiales" que no importa lo que hagan con ellos que no son capaz de "morir"; son procesos que están ahí "muertos" y que no consumen memoria RAM ni CPU, pero que el sistema todavía reconoce como existentes y que no importa lo que se haga con ellos que se resisten a desaparecer... Dichos procesos son llamados procesos zombie y si bien no tienen que causar problemas de rendimiento, su sola aparición hace que pensemos que dicho proceso está activo y pueden dar lugar a confusiones; es por eso que lo ideal es que ninguno de dichos zombies pululen por nuestro sistema operativo, por muy inofensivos que éstos sean.

Los procesos zombie siempre son procesos dependientes de un proceso "padre" que no ha sido capaz de finalizar correctamente sus procesos "hijo", haciendo que estos sigan existiendo en el sistema aún cuando no consuman recursos... Este fenómeno es fácilmente comprobable en cualquier consola de Linux; pero antes, para asegurarnos que efectivamente va a existir un proceso zombie, crearemos varios "zombies" nosotros mismos a modo de prueba de concepto. Para ello tendríamos que crear un pequeño programa escrito en c llamado, por ejemplo, zombiegen.c cuyo contenido sería:
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. int main() {
  4.         pid_t pid;
  5.         int i=0;
  6.         while (1)  {
  7.                 pid = fork();
  8.                 if (pid > 0) {
  9.                         // Proceso padre
  10.                         printf("Padre %d\n",+ 1);
  11.                         sleep(1);
  12.                 } else {
  13.                         // Proceso hijo
  14.                         printf("Zombie %d\n",+ 1);
  15.                         exit(0);
  16.                 }
  17.         i++;
  18.         }
  19.         return 0;
  20. }

Después habría que compilar el programa mediante gcc tal que así:
gcc zombie.c -o zombie
Con esto haríamos que se creasen constantemente procesos zombie hasta que decidiésemos parar el programa. ¿Cómo podemos saber si el sistema tiene algún proceso zombie actualmente? Mediante el siguiente comando:
ps aux |grep defunct |grep-vgrep
Al ser un bucle que crea procesos zombie constantemente podemos encontrarnos con algo como esto:

Si os fijáis bien en la línea en cuestión, veréis que una de sus columnas tiene una única letra; Z. Dicha Z significaría que dicho proceso tiene la etiqueta zombie, y que si bien no está operativo, dicho proceso en sí sigue existiendo en el sistema. Además veríamos también que todos los procesos finalizan con <defunct> que significaría que el proceso está parado, pero que todavía existe.
Ahora bien, ¿Cómo nos libramos de los zombies?  Tan simple como matando al padre de todos éstos, con lo que lo primero que tendríamos que ver es... ¿Quien es el padre de todos estos? Si conociésemos el PID (process ID) del padre, podríamos "matar" este para así automáticamente acabar con sus hijos... Esto puede parecer complejo pero es tan sencillo como hacer:
ps-eo pid,ppid,command|grep defunct |grep-vgrep
Con esto listaríamos el numero de proceso de cada zombie, seguido del número de proceso de aquel que ha "creado" el zombie, junto con el comando.
En mi caso en particular me aparecería esto:

Si nos fijamos bien, veremos que todos comparten el mismo PPID (Parent Process ID) ... Es decir que todos dependen de dicho proceso para seguir existiendo así que únicamente tendríamos que acabar con éste proceso mediante un simple kill. En este caso tendríamos que detener el proceso con PID 4636.
kill-94636
Tras lo cual únicamente tendríamos que volver a ejecutar nuestro anterior comando para ver que efectivamente hemos acabado con todos ellos.

Como veis, el encontrar y acabar con estos procesos es muy sencillo; solamente hay que buscar procesos "defunct" y acabar con el proceso que los está generando... Obviamente para acabar con la raíz del problema habría que ver qué error de programación hay en el proceso padre, pero esto puede servirnos como una solución temporal para limpiar los procesos zombie hasta encontrar el verdadero origen de esta situación.
Espero que os haya resultado útil.
Saludos.