Что означает ошибка зомби-процесс
Зомби-процесс (в списках отображается как defunct и имеет статус Z) — это запись в таблице процессов, оставшаяся после завершения дочернего процесса. Сам «зомби» не потребляет CPU и почти не использует память, но удерживает свой PID и занимает слот в таблице. Если накопится много таких записей, система может отказать во fork новых процессов. Выглядит это примерно так:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
www-data 12345 0.0 0.0 0 0 ? Z 09:10 0:00 [php] <defunct>
Ошибка проявляется, когда приложение или демон порождает дочерние процессы, но не дожидается их завершения через системный вызов wait/waitpid.
Причины возникновения
- Родительский процесс содержит ошибку и не обрабатывает завершение дочерних (нет вызова
wait). - Демон или скрипт использует
fork, но завершается сам до того, как дочерние процессы успевают завершиться. - Сбои в стороннем ПО или контейнерах, где менеджмент процессов настроен некорректно.
- Перегрузка или резкий скачок нагрузки, из-за которого родитель «не успевает» забрать статусы завершившихся детей.
- Ручной запуск команд в фоне без должного контроля (например, через
&в скриптах без последующегоwait).
Способы решения
Способ 1: Перезапуск родительского сервиса
Самый надёжный и часто применяемый метод — аккуратно перезапустить процесс, который породил зомби. Для системных служб используйте systemctl:
# Найти родителя
ps -eo stat,pid,ppid,cmd | grep '^Z'
# Перезапустить службу (пример для веб-сервера)
sudo systemctl restart nginx
Если это ваше приложение, перезапустите его корректно:
# Завершить родителя мягко
kill -TERM <PPID>
# Или, если требуется, перезапустить через supervisor/pm2
pm2 restart app-name
⚠️ Важно: если родитель — init (PID 1) или вы не понимаете, за что он отвечает, не завершайте его принудительно. Перезапускайте только те службы, чья роль вам известна.
Способ 2: Принудительная очистка через временный перезапуск родителя
Если перезапуск службы невозможен или нежелателен, можно заставить родителя перечитать конфигурацию (SIGHUP), что иногда приводит к корректной уборке зомби:
kill -HUP <PPID>
Проверьте, исчез ли зомби:
ps -eo stat,pid,ppid,cmd | grep '^Z'
Если процесс игнорирует сигналы, возможно, потребуется плановое техническое окно для полного перезапуска.
Способ 3: Исправление кода или настройки приложения
Если зомби появляются регулярно, проблема, скорее всего, в коде или конфигурации приложения. Для скриптов и демонов убедитесь, что после fork вызывается ожидание дочернего:
import os
import sys
import time
pid = os.fork()
if pid == 0:
# Дочерний процесс
time.sleep(1)
sys.exit(0)
else:
# Родительский процесс — обязательно дождаться завершения
os.waitpid(pid, 0)
Для сторонних приложений:
- Проверьте документацию и обновите ПО до версии, где исправлен менеджмент процессов.
- Включите опции вроде
--reapили настройте правила перезапуска в systemd (например,KillMode=mixedиRestart=on-failure).
Профилактика
- Регулярно проверяйте наличие зомби:
ps -eo stat,pid,ppid,cmd | grep '^Z'. - Включите мониторинг (например, через
cron+ уведомления), если процессы создаются в большом объёме. - Избегайте «вечных» циклов с
forkбез ожидания; всегда используйтеwait/waitpidили соответствующие абстракции (supervisord, systemd). - Обновляйте ПО и ОС, чтобы получать исправления, связанные с менеджментом процессов.
- Для критичных сервисов настройте
systemdс правильнымKillModeи политиками перезапуска, чтобы минимизировать последствия ошибок в коде.