Ответ
Процесс становится зомби (состояние Z в выводе ps или top), когда он завершил своё выполнение (exit), но его родительский процесс ещё не прочитал его статус завершения с помощью системного вызова wait() (или waitpid()).
Механика:
- Дочерний процесс завершается, отправляя родителю сигнал
SIGCHLD. - Операционная система сохраняет запись о процессе и его статусе завершения (код выхода, сигнал) в таблице процессов.
- Эта запись остаётся там до тех пор, пока родитель не вызовет
wait(). Пока запись существует, процесс считается "зомби". - После вызова
wait()ОС удаляет запись о зомби-процессе.
Пример на bash, демонстрирующий появление зомби:
#!/bin/bash
# Запускаем дочерний процесс в фоне и сразу завершаем его
sleep 10 &
# Немедленно завершаем родительский скрипт, не дожидаясь дочернего процесса.
# В этот момент дочерний `sleep` ещё выполняется.
# Когда `sleep` завершится, его родителем станет процесс с PID 1 (init),
# который периодически вызывает wait() и очищает зомби.
# Но если бы родительский процесс остался жив и игнорировал SIGCHLD,
# дочерний процесс стал бы зомби.
exit 0
Влияние на систему и устранение:
- Зомби-процессы не потребляют память (кроме небольшой записи в таблице процессов), но занимают PID.
- Длительное существование множества зомби может исчерпать доступные PIDs.
- Чтобы избежать зомби, родительский процесс должен:
- Регулярно вызывать
wait()для завершённых потомков. - Установить обработчик сигнала
SIGCHLDс вызовомwaitpid()с флагомWNOHANGдля асинхронной очистки. - В крайнем случае — явно игнорировать сигнал
SIGCHLD(signal(SIGCHLD, SIG_IGN)), что заставит ядро немедленно очищать дочерние процессы (но это не всегда переносимо).
- Регулярно вызывать