Зомби-процесс (zombie, defunct) — процесс, который завершил выполнение, освободил все ресурсы (память, файловые дескрипторы), но его запись всё ещё присутствует в таблице процессов ядра. Состояние обозначается как Z в выводе ps aux или как <defunct> в top. Зомби не потребляет CPU или RAM, но занимает PID — ценный ресурс ограниченного размера.
Как возникает
Механизм появления зомби:
- Родительский процесс (parent) создаёт дочерний (
fork()). - Дочерний процесс завершается и отправляет сигнал SIGCHLD родителю.
- Родитель должен вызвать
wait()илиwaitpid()для считывания exit-статуса дочернего процесса. - Если родитель не вызывает
wait()(занят, содержит баг, игнорирует SIGCHLD) — запись дочернего процесса остаётся в таблице как зомби.
Единственная информация, которую ядро хранит в зомби-записи — PID, UID, exit-статус и время CPU.
Как обнаружить: ps aux | grep Z или ps aux | awk '$8=="Z" {print $0}'. Количество зомби: cat /proc/loadavg | awk '{print $4}' (формат X/Y, где Y — общее число процессов, X — runnable).
Как удалить
Убить зомби напрямую (kill -9 <pid>) невозможно — процесс уже мёртв. Методы устранения:
- Отправить SIGCHLD родителю:
kill -SIGCHLD <ppid>— родитель может обработать накопившиеся сигналы и вызвать wait(). - Убить родительский процесс: при гибели родителя все его дочерние зомби усыновляет init (PID 1), который немедленно вызывает wait() и очищает их из таблицы.
- Перезагрузить сервер: если родитель — сам init или критический демон, хард-ребут — единственный вариант.
История
Термин "zombie process" появился в ранних версиях Unix (Bell Labs, 1970-е). Назван по аналогии с зомби из фольклора: тело (запись в таблице) существует, но жизни (ресурсов) нет. Механизм wait()/SIGCHLD описан в стандарте POSIX. Проблема зомби актуальна при разработке серверных приложений, использующих fork() без правильной обработки SIGCHLD.
На что обращать внимание
Несколько зомби — норма и не опасно. Сотни или тысячи зомби истощают пространство PID (по умолчанию max_pid = 32768 в Linux 32-bit, 4194304 в 64-bit). При исчерпании PID ни один новый процесс запустить невозможно — сервер фактически перестаёт работать. Для серверных приложений на C/C++ используйте sigaction(SIGCHLD, SA_NOCLDWAIT) или двойной fork() для предотвращения зомби. В PHP, Python, Node.js — следите за правильным завершением дочерних процессов в пулах воркеров (PHP-FPM, multiprocessing).
История и природа зомби-процессов
Концепция zombie-процесса появилась в Unix с момента создания модели процессов (Bell Labs, 1969). Первое упоминание термина «zombie» в контексте процессов — Version 7 Unix (1979), страница man ps. Зомби не потребляют CPU или память, но занимают запись в таблице процессов ядра. Максимум процессов в Linux определяется /proc/sys/kernel/pid_max (по умолчанию 32768 или 4194304 на 64-bit). Накопление тысяч зомби исчерпывает PID-пространство.
Почему возникают зомби-процессы
Зомби появляются когда: родительский процесс не вызывает wait() или waitpid() для считывания exit-статуса дочернего. Баги в коде приложений — частая причина. Zombie-процессы удаляются автоматически после гибели родителя (init/systemd усыновляет и «пожинает» их). Команды диагностики:
ps aux | grep Z # найти зомби (stat = Z)
ps -eo ppid,pid,stat,comm | grep Z # с PPID родителя
kill -SIGCHLD $(ppid) # сигнал родителю для очистки
На хостинге: когда зомби — проблема
На VPS с PHP-FPM: зомби возникают при неправильной конфигурации pm = dynamic с высоким max_children. В Docker: используйте --init флаг (tini) — он правильно управляет дочерними процессами. Мониторинг количества зомби через Zabbix или Prometheus node_exporter (метрика node_processes_state{state="Z"}).
Типичные ошибки
- Попытка убить зомби через
kill -9 PID— не работает, зомби уже мёртв. - Игнорирование роста числа зомби — признак утечки в родительском процессе.
- Перезагрузка сервера как метод борьбы с зомби — только маскирует проблему в коде.