- Un proceso zombie es un hijo ya terminado que sigue en la tabla de procesos porque su padre no ha llamado a wait().
- Se detectan con comandos como ps y top, donde aparecen con estado Z o etiquetados como <defunct>.
- No consumen CPU, pero muchos zombies pueden llenar la tabla de procesos y causar problemas serios.
- La limpieza correcta pasa por forzar al proceso padre a recoger el estado del hijo, usando señales como SIGHUP o SIGCHLD.
En el mundo de GNU/Linux y otros UNIX, hablar de procesos zombie no tiene nada que ver con series de televisión ni películas de terror, aunque el nombre les venga que ni pintado. Son esos procesos medio muertos, medio vivos, que se quedan pululando en la tabla de procesos y que, si se acumulan, pueden dar más de un quebradero de cabeza al administrador del sistema.
Conviene entender bien qué son, cómo se crean, cómo detectar procesos zombie en Linux (y en macOS) y, sobre todo, cómo eliminarlos sin cargarnos nada importante. A continuación verás una explicación detallada, combinando teoría del sistema, ejemplos prácticos con comandos como ps o top, varios métodos para matar estos procesos difuntos y hasta un pequeño programa en C para generar un zombie de prueba.
Qué es exactamente un proceso zombie en Linux
Un proceso zombie (o defunct) es un proceso hijo que ya ha terminado su ejecución, pero que aún conserva una entrada en la tabla de procesos del sistema. Esa entrada permanece para que su proceso padre pueda consultar el código de salida del hijo mediante llamadas como wait() o waitpid(). Hasta que el padre no hace esa lectura, el hijo no desaparece del todo.
Desde un punto de vista metafórico, el hijo ha muerto, pero su “alma” sigue registrada en el sistema. Por eso se les llama zombies o difuntos: ya no están ejecutando código, no consumen CPU ni memoria de usuario, pero sí ocupan un pequeño hueco en la tabla de procesos. Si hay uno o dos no pasa nada, pero si una aplicación mal programada genera muchos, podemos llegar a tener problemas.
En sistemas Unix y Linux, cuando un proceso termina, el kernel libera sus recursos (memoria, descriptores de fichero, etc.), pero conserva esa ficha mínima con el estado de salida. Si el padre nunca llama a wait(), esa ficha no se limpia, y el proceso queda marcado como zombie. Es decir, se trata casi siempre de un problema de programación o de diseño del software que ejerce como proceso padre.
Estos procesos se reconocen fácilmente porque en herramientas como ps aparecen con el estado Z (de zombie) o con la etiqueta <defunct>, y en monitores como top hay contadores específicos que muestran cuántos zombies tenemos activos en el sistema en un momento dado.

Estados de los procesos en Linux
Para entender el papel de los zombies, viene bien repasar los estados de proceso más habituales en Linux. Cuando listamos procesos con ps o top, se usa una letra para indicar el estado:
- Sleeping (S): procesos durmiendo, esperando a que les toque ejecutarse o a que ocurra algún evento.
- Running (R): procesos que están ejecutándose en CPU o listos para ejecutarse.
- Waiting (D): procesos bloqueados esperando la finalización de una operación de entrada/salida (espera ininterrumpible).
- Stopped (T): procesos detenidos, por ejemplo, mediante señales como SIGSTOP o porque están en modo depuración.
- Zombie (Z): procesos que han terminado, pero siguen apareciendo en la tabla de procesos esperando a que su padre lea su estado de salida.
Cada línea de ps muestra un proceso con su PID, PPID (PID del padre), usuario, estado y otros datos. El campo de estado puede llamarse S, STAT o similar, según los parámetros de ps. Un proceso con estado Z es, oficialmente, un zombie. En muchos casos, el comando o nombre del proceso se mostrará como <defunct>, lo que deja claro que es un difunto.
Cómo detectar procesos zombie en Linux desde la terminal
La forma más directa de localizar procesos zombie es tirar de los clásicos comandos de monitorización: ps y top. Combinarlos con herramientas como grep, awk o xargs permite filtrar y preparar listas de PIDs con bastante precisión.
Uno de los comandos más usados para ver zombies es:
ps -el | grep ‘Z’
El parámetro -el hace que ps muestre una salida extendida, donde la segunda columna suele indicar el estado del proceso. En esa columna podemos encontrar, entre otros:
- S: sleeping.
- R: running.
- D: waiting (espera ininterrumpible).
- T: stopped o gestopt (suspendido).
- Z: zombie (defunct).
Si quieres un ejemplo más detallado, en una máquina con procesos problemáticos podríamos obtener algo como:
ps -el | grep ‘Z’
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
1 Z 0 1213 589 0 75 0 – 0 funct> ? 00:00:00 dovecot-auth
Aquí vemos que el proceso dovecot-auth está marcado con estado Z, así que es un zombie. Fíjate también en la columna PPID, porque ese es el PID del proceso padre del que luego hablaremos para poder limpiar el zombie correctamente.
Otra forma muy habitual de listar zombies es usar la combinación:
ps -A -ostat,ppid,pid,cmd | grep -e ‘^’
En este caso, con -A listamos todos los procesos y la opción -o nos permite definir exactamente las columnas que queremos: estado (stat), PPID, PID y el comando. El filtro grep -e ‘^’ se queda solo con las líneas cuyo estado comience por Z o z, es decir, procesos zombies.
Otra variante, algo más minimalista, sería:
ps axo pid=,stat= | awk ‘$2~/^Z/ { print $1 }’
En esta versión, pedimos solo el PID y el estado, sin encabezados (con pid=,stat=), y luego con awk filtramos las filas cuyo campo de estado empiece por Z, imprimiendo únicamente el PID del proceso zombie. Es una forma elegante de generar una lista de PIDs zombie para utilizarla después con kill o con otras tuberías.

Uso de top para localizar procesos zombie
El comando top es una herramienta interactiva muy cómoda para ver en tiempo real lo que está ocurriendo en el sistema. En la cabecera de top se muestra un resumen donde aparece el número total de tareas y cuántas están en cada estado, incluyendo cuántos zombies hay activos en ese momento.
Para usarlo, basta con ejecutar:
top
En la primera o segunda línea verás algo del estilo: Tasks: 150 total, 1 running, 149 sleeping, 0 stopped, 1 zombie. Ese contador de zombies ya te dice si hay procesos difuntos colgando del sistema. Además, al bajar por la lista de procesos, en la columna S (estado) podrás localizar fácilmente aquellos marcados con una Z.
Una limitación de top es que, aunque indica cuántos zombies hay, no siempre es igual de cómodo que ps para extraer sólo esos procesos. Por eso es muy habitual combinarlos: primero se ve en top si hay zombies, y después se usa ps con los filtros que hemos visto para identificarlos con detalle y preparar los comandos que los van a eliminar.
En algunos artículos también se sugiere otro comando específico para ver procesos defunct con más información:
ps axo stat,ppid,pid,comm | grep -w defunct
Este comando se centra en procesos cuyo comando está marcado como defunct; de nuevo verás el estado, el PID del padre, el PID del hijo y el comando asociado, lo que facilita mucho seguir el rastro del problema hasta el proceso padre.

Qué ocurre en el kernel con un proceso zombie
A nivel interno del kernel de Linux, cada proceso se representa mediante una estructura de datos llamada struct task_struct. Dentro de esa estructura existen campos que indican el estado del proceso, entre ellos exit_state, que es donde se almacena el estado de salida cuando el proceso termina.
Cuando un proceso acaba, el kernel marca ese proceso con un valor como EXIT_ZOMBIE (definido en los encabezados del kernel) dentro de ese campo exit_state. Esto significa que el proceso ya ha terminado, pero aún está pendiente de que el padre recoja la información de salida. Mientras el padre no ejecute wait(), el kernel no cambia ese estado ni elimina por completo la entrada de la tabla de procesos.
El detalle interesante es que, aunque un zombie no consuma CPU ni memoria de trabajo significativa, sí ocupa un slot en la tabla de procesos. Y esa tabla tiene un tamaño finito. Si una aplicación está creando hijos en bucle que nunca son limpiados (porque el padre no llama a wait()), podríamos acabar con cientos o miles de zombies, agotando la capacidad de la tabla y causando fallos al crear nuevos procesos.
Cómo terminar procesos zombie en Linux
Una vez que hemos detectado que hay procesos zombie, toca pensar en cómo «matarlos» de forma efectiva. Aquí hay un punto clave: el proceso zombie ya está muerto, en el sentido de que no está ejecutándose. Por tanto, enviar señales como SIGKILL (kill -9) directamente al zombie no sirve de nada; no hay código que atender esa señal.
Lo que realmente hay que hacer es conseguir que el proceso padre lea el estado de salida del hijo. Esto se puede lograr de varias formas: enviando señales apropiadas al padre, obligando al padre a terminar (de modo que init o systemd adopten al zombie y lo limpien), o utilizando combinaciones de comandos que automaticen esa labor.
Primera opción: enviar SIGHUP al padre
Una solución muy extendida consiste en encontrar el PPID de los procesos zombie y enviar una señal al padre para que ejecute wait() y recoja los estados de sus hijos. Un comando típico es:
kill -HUP `ps -A -ostat,ppid,pid,cmd | grep -e ‘^’ | awk ‘{print $2}’`
Aquí se hace lo siguiente: primero se listan todos los procesos con su estado, PPID, PID y comando; luego se filtran aquellos cuyo estado empieza por Z; finalmente, con awk ‘{print $2}’ se extrae la segunda columna, que es el PPID (el identificador del proceso padre). Esa lista de PIDs padres se pasa a kill -HUP, que envía la señal SIGHUP a cada uno.
Esa señal, en muchas aplicaciones, provoca que el proceso padre recargue su configuración o haga cierta limpieza. En este contexto, la idea es que el padre haga un wait() apropiado y se deshaga de los zombies. Es un método bastante agresivo pero práctico, sobre todo cuando hay muchos zombies acumulados y se sabe que comparten el mismo proceso padre.
Segunda opción: usar SIGCHLD
Otro enfoque consiste en enviar la señal SIGCHLD al proceso padre problemático. Esta señal indica a un proceso que uno de sus hijos ha cambiado de estado (por ejemplo, ha terminado). Normalmente, cuando un proceso hijo muere, el kernel envía SIGCHLD al padre; si el padre tiene un manejador de señal configurado, suele llamar a wait() dentro de ese manejador.
Si detectas que varios zombies tienen el mismo PPID, puedes intentar:
kill -s SIGCHLD <PPID>
Por ejemplo:
kill -s SIGCHLD 2201
Con esto le estás recordando al padre que tiene hijos muertos pendientes. Si el proceso padre está bien programado para reaccionar a SIGCHLD, limpiará a sus zombies utilizando wait(). Este método es menos brusco que terminar al padre y, si el programa está correctamente escrito, es la forma más natural de resolver el problema.
Tercera opción: matar al proceso padre
Si el proceso padre está bloqueado, no responde a señales como SIGHUP o SIGCHLD, o claramente está colgado, otra opción es terminarlo por las malas. En este caso se recurre al clásico:
kill -9 <PPID>
Por ejemplo:
kill -9 2201
Al hacer esto, el kernel elimina al proceso padre. En la mayoría de sistemas modernos, systemd o el proceso init adoptan los huérfanos (incluidos los zombies) y se encargan de llamar a wait() sobre ellos, con lo que se limpia su entrada en la tabla de procesos. No es lo más elegante, pero en ocasiones es la única forma de quitarse de encima una colección de zombies originados por un programa defectuoso.
Otras combinaciones avanzadas con ps, awk y kill
Además de los ejemplos anteriores, existen muchos «one-liners» que automatizan la búsqueda de zombies y el envío de señales a sus procesos padres. Algunos ejemplos representativos son:
ps axo state,pid | awk ‘$1==»2″ {print $2}’ | xargs kill -s SIGKILL
Este comando selecciona procesos basándose en el valor numérico del estado; sin embargo, se usa menos porque resulta menos legible que trabajar con la letra Z. Otros comandos habituales para tratar zombies son:
ps -xaw -o state,ppid | grep Z | grep -v PID | awk ‘{ print $2 }’ | xargs kill -9
o bien:
kill -9 `ps xawo state=,pid= | sed -n ‘s/Z //p’`
o incluso:
kill -9 `ps -xaw -o state -o ppid | grep Z | grep -v PID | awk ‘{print $2}’`
En todos los casos, la idea es parecida: localizar procesos con estado Z, extraer sus PIDs o los PPIDs correspondientes y aplicar kill con la señal que consideremos adecuada (SIGHUP, SIGCHLD, SIGKILL, etc.). Eso sí, hay que usar estas recetas con cierto cuidado, porque matar procesos padres importantes sin pensarlo dos veces puede dejar servicios caídos o el sistema inestable.
Ejemplo práctico: crear un proceso zombie con C
Para poder hacer pruebas sin estropear nada, una técnica clásica es crear un proceso zombie de forma controlada con un pequeño programa en C. De este modo podemos ver exactamente cómo aparece en ps, cómo se marca como <defunct> y practicar los comandos para eliminarlo.
Un programa muy sencillo que genera un zombie podría ser este:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
pid_t child_pid;
child_pid = fork ();
if (child_pid > 0) {
sleep (60);
}
else {
exit (0);
}
return 0;
}
En este código, el proceso padre hace un fork(). El hijo termina inmediatamente con exit(0), mientras que el padre se queda durmiendo 60 segundos. Durante ese tiempo, el hijo está muerto pero el padre aún no ha llamado a wait(), así que el hijo permanece en estado zombie en la tabla de procesos.
Para compilar este programa puedes usar gcc de la siguiente forma:
gcc -o zombie1 zombie.c
Y para ejecutarlo en segundo plano, simplemente:
./zombie1 &
Mientras el padre siga dormido, podrás ejecutar ps -el | grep ‘Z’ o cualquiera de los comandos anteriores y verás tu proceso zombie en acción. Tras unos segundos, cuando el padre termine y el sistema limpie el proceso, el zombie desaparecerá.
Impacto de los procesos zombie y causas habituales
Un solo proceso zombie, aislado, no suele ser preocupante. No consume CPU, la memoria asociada al proceso ya se ha liberado y el impacto directo en el rendimiento es mínimo. El problema viene cuando se acumulan muchos zombies, normalmente porque un software está mal diseñado o tiene bugs en la gestión de procesos hijos.
Las causas más frecuentes de zombies son:
- Mala programación: el proceso padre crea procesos hijos pero no implementa correctamente la gestión de SIGCHLD ni llama a wait() o waitpid() para recoger el estado de los hijos.
- Errores de configuración: algunos servicios pueden crear procesos hijos en bucle bajo ciertas configuraciones no previstas por el desarrollador, generando una cascada de zombies.
- Cuelgues o bloqueos del proceso padre: si el padre se queda bloqueado en una operación de E/S o en un bucle infinito, puede dejar hijos muertos sin limpiar.
Cuando hay muchos procesos zombie, la tabla de procesos puede llenarse de entradas difuntas, dificultando la creación de nuevos procesos y generando síntomas como lentitud, errores al lanzar aplicaciones o comportamientos raros en servicios críticos (por ejemplo, servidores web como Apache generando cientos de procesos defunct).
Por todo ello, es importante revisar de vez en cuando con top o ps si hay zombies, especialmente en servidores en producción, y, sobre todo, corregir la causa de fondo: actualizar el software problemático, corregir el código que maneja procesos hijos o ajustar configuraciones que están provocando la creación descontrolada de hijos.
Alternativas gráficas para usuarios de escritorio
Si no te sientes cómodo manejando la terminal o simplemente prefieres una solución visual, en muchos entornos gráficos de Linux puedes apoyarte en el Monitor del Sistema (System Monitor) o herramientas equivalentes que ofrecen una vista gráfica de los procesos.
El procedimiento general sería algo así:
- Abrir la aplicación de Monitor del Sistema desde el menú de tu escritorio.
- Ir a la pestaña de Procesos, donde se listan todos los procesos activos.
- Usar la herramienta de búsqueda (normalmente un icono de lupa) para buscar términos como zombie o fijarte en la columna de estado para localizar procesos marcados como <defunct> o Z.
- Seleccionar el proceso problemático, hacer clic con el botón derecho y elegir la opción de “Matar” o “Finalizar proceso”.
Para que esto funcione correctamente, es clave asegurarse de que el monitor está mostrando todos los procesos del sistema y no sólo los del usuario actual. Normalmente hay una casilla o una opción en la configuración que permite «Mostrar procesos de todos los usuarios» o similar.
Buenas prácticas para evitar la proliferación de zombies
Más allá de los trucos para matar zombies cuando ya han aparecido, merece la pena aplicar algunas buenas prácticas para reducir al mínimo la aparición de estos procesos en sistemas de producción.
Entre las recomendaciones más importantes están:
- Mantener el sistema y el software actualizado: muchas veces, los procesos zombie vienen de bugs ya corregidos en versiones posteriores de un servidor o aplicación.
- Revisar la programación de procesos hijos: si desarrollas software que usa fork(), asegúrate de manejar correctamente SIGCHLD y de llamar a wait() o waitpid() para cada hijo que termina.
- Monitorizar de forma periódica: incorporar comandos como ps -el, ps axo stat,ppid,pid,comm o top en scripts de monitorización o herramientas de observabilidad ayuda a detectar de inmediato picos de zombies.
- Investigar el origen cuando aparecen zombies recurrentes: si siempre son hijos de un servicio concreto (por ejemplo, un servidor de correo o un demonio concreto), quizá toque revisar su configuración o su versión.
En alguna ocasión se han publicado incluso scripts específicos (por ejemplo, llamados zombi.sh) que automatizan toda esta lógica: localizan zombies, identifican a sus procesos padres, envían las señales adecuadas e intentan limpiar la tabla de procesos. Son útiles como última carta cuando los métodos manuales fallan, pero siempre es importante saber qué están haciendo por debajo para no llevarse sorpresas.
En definitiva, entender qué es un proceso zombie, cómo verlo con ps y top, cómo actúan las señales SIGHUP, SIGCHLD y SIGKILL sobre los procesos padres y qué patrones de programación llevan a este estado te permite diagnosticar y resolver con soltura prácticamente cualquier problema relacionado con procesos difuntos en Linux, manteniendo tus sistemas más limpios, estables y con la tabla de procesos bajo control.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.