Как возникает зомби-процесс (zombie process) в Linux?

Ответ

Зомби-процесс (состояние Z в ps aux) возникает, когда дочерний процесс завершил свое выполнение (с помощью exit() или получив фатальный сигнал), но его родительский процесс еще не вызвал системный вызов wait() или waitpid() для получения его статуса завершения. Пока родитель не прочитает этот статус, запись о процессе остается в таблице процессов ядра.

Практический пример на Bash:

#!/bin/bash
# Родительский скрипт запускает фоновый процесс и не ждет его завершения
sleep 10 &
echo "Дочерний процесс запущен в фоне, PID: $!"
# Родительский скрипт завершается НЕМЕДЛЕННО, не дожидаясь sleep
exit 0

Если запустить этот скрипт и быстро выполнить ps aux | grep sleep, можно увидеть процесс sleep в состоянии Z (зомби), пока его не "приберет" родитель (обычно init/PID 1).

Ключевые моменты:

  • Зомби не потребляют память или CPU: Они лишь занимают запись в таблице процессов. Проблема возникает, если таких записей становится слишком много (лимит pid_max).
  • Уборка зомби: Если родительский процесс завершается, его зомби-потомки усыновляются процессом init (с PID 1), который периодически вызывает wait() для их очистки.
  • Отладка: Для поиска зомби-процессов используйте ps aux | awk '$8=="Z" {print $0}'. Чтобы избежать их появления в своих программах, необходимо корректно обрабатывать сигнал SIGCHLD или использовать wait() в родительском процессе.

Ответ 18+ 🔞

Да ты посмотри, какая дичь бывает в системе! Вот представь: процесс отработал, по сути уже труп, а в таблице процессов его запись как призрак болтается — это и есть зомби, состояние Z в ps aux. Возникает эта хрень, когда дочерний процесс уже сдох (через exit() или от фатального сигнала), а его родитель-растяпа ещё не вызвал wait() или waitpid(), чтобы статус завершения прочитать. Пока не прочитает — запись в ядре висит, как манда с ушами.

Практический пример на Bash, чтоб совсем понятно стало:

#!/bin/bash
# Родительский скрипт запускает фоновый процесс и не ждет его завершения
sleep 10 &
echo "Дочерний процесс запущен в фоне, PID: $!"
# Родительский скрипт завершается НЕМЕДЛЕННО, не дожидаясь sleep
exit 0

Запусти эту подлянку и быстро глянь ps aux | grep sleep — увидишь, как sleep торчит в состоянии Z, пока его родитель (или уже init) не приберёт.

Что тут важно уяснить, чтобы не бздеть попусту:

  • Зомби — они как тени: Памяти или CPU не жрут, просто место в таблице процессов занимают. Но если их овердохуища накопится (до лимита pid_max), тогда уже беда.
  • Кто уборщик: Если родительский процесс сам накрылся медным тазом, его зомби-детей забирает процесс init (PID 1). Он уж за ними периодически wait() вызывает и подчищает.
  • Как искать и не плодить: Чтобы найти этих призраков, гони ps aux | awk '$8=="Z" {print $0}'. А чтобы в своих программах такого не было — обрабатывай сигнал SIGCHLD как человек, либо wait() используй. А то потом волнение ебать, куда процессы деваются.