Ответ
Зомби-процесс (zombie, defunct) — это процесс, который завершил своё выполнение (его код и ресурсы освобождены), но его запись остаётся в таблице процессов операционной системы. Это происходит потому, что родительский процесс ещё не прочитал статус завершения своего дочернего процесса с помощью системного вызова wait() или waitpid().
Ключевые характеристики зомби:
- Не потребляет CPU и память: Код процесса и его данные уже освобождены. Зомби занимает только запись в таблице процессов (PID и минимальная метаинформация).
- Не может быть "убит": Сигнал
SIGKILLна зомби не действует, так как процесс уже мёртв. - Исчезает автоматически: Когда родительский процесс, наконец, вызывает
wait(), ядро передаёт ему статус завершения и окончательно удаляет запись о зомби. Если родительский процесс завершается, все его зомби-поты «усыновляются» процессомinit(PID 1), который периодически вызываетwait()и очищает их.
Проблема для DevOps: Большое количество зомби-процессов (тысячи) может исчерпать доступные PIDs в системе, что помешает созданию новых процессов. Это часто указывает на баг в родительском процессе, который не обрабатывает завершение своих потомков.
Как обнаружить зомби:
# Статус 'Z' в выводе ps означает зомби
$ ps aux | grep 'Z'
USER PID PPID STAT COMMAND
appuser 4567 1234 Z [defunct-process]
# Или с помощью top, посмотрев на количество зомби в заголовке
$ top
...
Tasks: 100 total, 1 running, 98 sleeping, 0 stopped, 1 zombie
...
Типичные причины и отладка:
- Родитель в бесконечном цикле или заблокирован и не доходит до вызова
wait(). - Родитель неверно настроил обработчик сигнала
SIGCHLD. По умолчанию этот сигнал уведомляет родителя о завершении потомка. Если родитель явно игнорирует сигнал (signal(SIGCHLD, SIG_IGN)), ядро сразу очищает дочерние процессы, не превращая их в зомби. Но если родитель установил свой обработчик и в нём нет вызоваwait(), зомби будут накапливаться. - Для отладки используйте
strace -p <PPID>на родительском процессе, чтобы увидеть, делает ли он системные вызовыwait4илиwaitpid.
Решение: Исправить код родительского процесса, чтобы он корректно ожидал завершения дочерних процессов. В крайнем случае, если родитель "сломан", перезапуск родительского процесса очистит всех его зомби.