Что такое зомби процесс? Как появляются зомби процессы?
Зомби-процесс (zombie process) — это процесс, который завершил своё выполнение, но всё ещё присутствует в таблице процессов операционной системы в ожидании, пока родительский процесс прочитает его код завершения с помощью системного вызова wait() или waitpid().
🧠 Как устроено завершение процессов в Unix-подобных системах
Когда дочерний процесс завершает своё выполнение, он:
-
освобождает большую часть ресурсов: память, файловые дескрипторы, потоки и т.д.;
-
возвращает код завершения (exit status);
-
но его запись в таблице процессов остаётся, чтобы родитель мог забрать код завершения.
До тех пор, пока родитель не вызовет wait() или waitpid(), система не может полностью удалить этот процесс из таблицы.
Такой завершённый, но ещё не "убранный" процесс и называется зомби.
⚙️ Когда появляется зомби-процесс
Зомби-процессы появляются, если:
1. Родитель не ожидает завершения потомка
Если родительский процесс не вызывает wait() после завершения дочернего, то зомби-процесс остаётся в таблице процессов. Пример:
pid_t pid = fork();
if (pid == 0) {
// Дочерний процесс
exit(0); // Завершается
} else {
sleep(60); // Родитель спит и не вызывает wait()
}
Здесь дочерний процесс станет зомби, пока родитель "спит".
2. Родитель сам завершился, не вызвав wait()
Если родитель завершится до вызова wait(), дочерний процесс усыновляется процессом init (PID 1). init следит за своими "приёмными детьми" и автоматически вызывает wait(), так что зомби удаляются. Это поведение помогает избегать утечек.
3. Обработка сигнала SIGCHLD не настроена
Когда дочерний процесс завершается, он отправляет родителю сигнал SIGCHLD.
Если родитель не обрабатывает SIGCHLD (например, не установлена соответствующая signal или sigaction функция), то wait() не вызывается, и дочерний процесс остается в таблице как зомби.
🔍 Как увидеть зомби-процессы
В Linux можно воспользоваться командой ps:
ps aux | grep Z
Признаки:
-
в колонке STAT: Z — Zombie
-
в колонке CMD: часто <defunct>
Пример:
user 12345 0.0 0.0 0 0 ? Z 00:00 0:00 \[myproc\] <defunct>
📉 Почему зомби — это проблема
-
Таблица процессов ограничена
В системе существует ограниченное число PID (обычно ~32K, 64K или больше).
Если множество зомби остаются в таблице, это может привести к невозможности запуска новых процессов. -
Индикатор проблем в логике программы
Зомби — симптом плохого управления процессами.
В производственных системах это сигнал к багу: забыли wait(), неверно обработан SIGCHLD, неправильно написан обработчик.
🛠️ Как избавиться от зомби-процесса
1. Родитель должен вызвать wait() или waitpid()
pid_t pid;
while ((pid = wait(NULL)) > 0) {
printf("Reaped child %d\\n", pid);
}
-
wait(NULL) — дождётся любого завершившегося дочернего процесса.
-
waitpid(-1, NULL, WNOHANG) — позволяет не блокироваться, если ни один потомок не завершён.
2. Обработка сигнала SIGCHLD
В языке C:
void sigchld_handler(int s) {
// Убираем всех зомби
while(waitpid(-1, NULL, WNOHANG) > 0);
}
signal(SIGCHLD, sigchld_handler);
Таким образом, при завершении дочернего процесса — он сразу будет очищен.
3. Если родительский процесс не исправляется — убить родителя
-
Если родитель «забыл» удалить зомби и не делает wait(), можно:
-
убить родителя (если это возможно)
-
тогда процесс «init» станет новым родителем
-
init всегда очищает зомби автоматически
-
🧪 Пример создания зомби-процесса на bash
#!/bin/bash
( sleep 2 ) &
child_pid=$!
echo "Child PID: $child_pid"
sleep 10 # родитель не ждет завершения
-
Пока sleep 10 выполняется, дочерний процесс завершится через 2 секунды и станет зомби
-
ps -o pid,ppid,state,cmd -p $child_pid покажет состояние Z
🧱 Итого внутренний механизм:
-
Процесс завершает выполнение, вызывает exit()
-
Ядро сохраняет **exit status
** -
Процесс становится зомби
-
Родитель должен вызвать wait()/waitpid() чтобы забрать статус
-
После этого ядро полностью удаляет процесс из таблицы процессов
Таким образом, зомби — это кратковременное состояние завершившегося процесса, необходимое для правильного завершения взаимодействия между родителем и потомком.