При мониторинге системы Linux с помощью команды top вы можете заметить элемент в строке 'Задачи (Tasks)', например 1 зомби (zombie).

top - 16:03:19 up  7:09,  1 user,  load average: 2.24, 2.21, 2.29
Задачи: 392 всего,  1 выполняется, 390 ожидает,  0 остановлено,  1 зомби
...

Что такое этот 'зомби' и как это влияет на систему? В этой статье мы ясно объясним, что такое зомби-процесс (Zombie Process), как его обнаружить и решить проблему.


Что такое зомби-процесс (Zombie Process)? 🧟



Рассмотрим метафору жизненного цикла процесса для лучшего понимания.

  1. Рождение (Fork): родительский процесс (Parent Process) создает дочерний процесс (Child Process) (fork()).

  2. Исполнение (Exec): дочерний процесс выполняет свою задачу.

  3. Завершение (Exit): дочерний процесс завершает выполнение и выходит (exit()).

  4. Сбор (Wait): когда дочерний процесс завершен, операционная система (ядро) оставляет информацию о процессе, такую как PID и статус завершения, в таблице процессов. Затем отправляется сигнал SIGCHLD (дочерний процесс завершен) родительскому процессу.

  5. Родительский процесс, получив этот сигнал, должен вызвать системный вызов wait() для "сбора" информации о состоянии завершения дочернего процесса. Как только эта информация будет собрана, ядро окончательно удалит запись о дочернем процессе из таблицы процессов.

Зомби-процесс - это процесс, "застрявший" между 4-м и 5-м состоянием. То есть, дочерний процесс завершил выполнение, но родительский процесс еще не вызвал wait() для сбора его состояния.

Как следует из названия, этот процесс находится в мёртвом состоянии (не выполняется). Поэтому он не потребляет системные ресурсы, такие как CPU или память.

Почему зомби-процесс является проблемой?

Сами по себе зомби-процессы почти не используют ресурсы системы, но занимают один слот в таблице процессов (PID).

Если из-за ошибок родительского процесса зомби-процессы продолжают накапливаться и не удаляются, это может привести к исчерпанию максимального количества доступных PID в системе. В этом случае система больше не сможет создавать новые процессы, что может привести к серьезным сбоям. Наличие 1-2 зомби в top не является чем-то необычным, но если это число продолжает расти, необходимо принять меры.


Как проверить и идентифицировать зомби-процессы

Команда top показывает только _количество_ зомби-процессов. Чтобы узнать, какой процесс находится в состоянии зомби и кто его родитель, необходимо использовать команду ps.

Самый простейший способ — это найти процессы в состоянии 'Z' в колонке STAT команды ps.

# Отображение всех процессов с фильтром для состояния 'Z' (зомби)
ps -elf | grep ' Z '

# Или использовать опцию 'aux' (8-й столбец ($8) — состояние (STAT))
ps aux | awk '$8=="Z"'

Пример вывода :

# ps -elf | grep ' Z '
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
0 Z  user  5021  5000  0  80   0 -     0 exit   15:30 ?        00:00:00 [defunct]

В данном примере важная информация включает:

  • S (Состояние): Z (означает, что процесс в состоянии зомби)

  • PID: 5021 (это PID зомби-процесса)

  • PPID: 5000 (это PID родительского процесса, который не собрал зомби)

  • CMD: [defunct] (имя, указывающее на то, что процесс завершился, но не был собран)


Способы решения проблемы зомби-процессов



Самое важное, что нужно знать: зомби-процессы нельзя убить с помощью команды kill.

kill -9 5021 (PID зомби из примера выше)

Эта команда не сработает. Зомби уже в "мертвом" состоянии, и не существует субъекта, способного обработать сигнал kill.

Единственный способ решения проблемы зомби-процессов заключается в том, чтобы родительский процесс вызвал wait().

Шаг 1: Отправка сигнала родительскому процессу (рекомендуется)

Первое, что следует попробовать, — это вручную отправить сигнал SIGCHLD родительскому процессу (PPID) для проверки состояния дочернего процесса.

# Отправка сигнала SIGCHLD родительскому PID (5000) из примера выше
kill -s SIGCHLD 5000

Это указывает родительскому процессу: "Один из твоих дочерних процессов завершился, проверь это!". Если родитель правильно запрограммирован, он должен принять этот сигнал и собрать зомби.

Шаг 2: Принудительное завершение родительского процесса (последнее средство)

Если Шаг 1 не сработал, это может означать, что родительский процесс (PPID 5000) сам завис, или в его логике вызова wait() есть серьезная ошибка.

В этом случае принудительное завершение родительского процесса является единственным решением.

# Завершение родительского процесса (PPID 5000)
kill 5000

# Если всё еще не завершается, принудительное завершение
kill -9 5000

Почему завершение родителя решает проблему?

В Linux, когда родительский процесс завершается, дочерние процессы (сироты) автоматически "усыновляются" процессом init (PID 1) или systemd. Процесс init регулярно проверяет состояние своих дочерних процессов и оперативно собирает завершенные дочерние процессы (включая зомби).

Таким образом, когда проблемный родитель (PPID 5000) завершается, зомби (PID 5021) становится новым дочерним процессом init, и init немедленно очищает зомби.

⚠️ Внимание: Прежде чем завершить родительский процесс, обязательно проверьте, является ли этот процесс важной службой для системы (например, БД, веб-сервер и т. д.) с помощью команды ps -p 5000 (родительский PID). Принудительное завершение важной службы может привести к более серьезным сбоям.


Резюме

  • Зомби-процесс — это остаток в таблице процессов, который завершился, но родитель не собрал информацию о его завершении.

  • Он не потребляет ресурсы, но занимает PID, и если их слишком много, это может вызвать сбой системы.

  • Вы можете найти зомби (PID) и его родителя (PPID) с помощью команды ps -elf | grep ' Z '.

  • Решение направлено на родительский процесс (PPID), а не на зомби.

    1. kill -s SIGCHLD <родительPID> (рекомендуется)

    2. kill <родительPID> (последнее средство)