LinuxНизкая

Зомби-процессы в Linux: как найти и устранить

Статья объясняет природу зомби-процессов в Linux и предоставляет практические методы их устранения. Вы научитесь находить зомби-процессы и применять правильные команды для очистки системы.

Обновлено 16 февраля 2026 г.
10-15 мин
Низкая
FixPedia Team
Применимо к:Linux 5.x+Ubuntu 20.04+CentOS 8+Debian 11+

Что такое зомби-процесс в Linux

Зомби-процесс (zombie process) — это процесс, который уже завершил своё выполнение, но его запись остаётся в таблице процессов системы. Это происходит, когда родительский процесс не прочитал статус завершения дочернего процесса с помощью системного вызова wait() или его вариаций.

В выводе команды ps aux или top такой процесс отображается с состоянием Z. У зомби-процесса нет потребления процессорного времени или оперативной памяти, но он занимает запись в таблице процессов (и, следовательно, один из доступных идентификаторов процесса — PID).

Обычно зомби-процесс — это временное состояние, которое длится микросекунды. Однако если родительский процесс "забыл" о своём дочернем, зомби может оставаться в системе неопределённо долго.

Как выглядит ошибка?

$ ps aux | grep Z
USER       PID  %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1234   0.0  0.0      0     0 ?        Z    10:00   0:00 [defunct] <имя_процесса>

Символ [defunct] в колонке COMMAND явно указывает на зомби-процесс.

Причины возникновения

Зомби-процессы появляются по одной основной причине и нескольким косвенным:

  1. Родительский процесс не вызывает wait(). Это самая частая причина. После того как дочерний процесс завершается (например, через exit()), ядро сохраняет информацию о его завершении (код возврата, использование ресурсов) в структуре процесса. Родитель должен прочитать эту информацию с помощью wait() или waitpid(). Если родитель этого не делает, запись дочернего процесса остаётся в таблице процессов как "зомби".
  2. Родительский процесс "завис" или некорректно обрабатывает сигналы. Если родительский процесс игнорирует сигнал SIGCHLD (который ядро отправляет при завершении ребёнка) или сам завершился, не дождавшись детей, это приводит к появлению зомби.
  3. Ошибка в программе. В коде родительского процесса может отсутствовать вызов wait() после fork(), или он может быть заблокирован на другом действии (например, на ожидании ввода-вывода).
  4. Ошибка в системном скрипте или демоне. Некоторые старые или некорректно написанные демоны могут создавать зомби при обработке запросов.

Способы устранения зомби-процессов

Поскольку зомби-процесс уже мёртв, его нельзя "убить". Единственный способ освободить запись в таблице процессов — заставить родительский процесс прочитать статус завершения. Если родитель не может или не хочет этого сделать, нужно завершить самого родителя.

Способ 1: Отправить сигнал SIGCHLD родительскому процессу

Это самый аккуратный способ. Сигнал SIGCHLD (сигнал о завершении потомка) может заставить родительский процесс, который его корректно обрабатывает, вызвать wait() и "подобрать" зомби.

  1. Найдите PID родительского процесса (PPID) зомби-процесса (из вывода ps aux).
  2. Отправьте ему сигнал:
    kill -SIGCHLD <PPID>
    
    или просто:
    kill -18 <PPID>
    
  3. Проверьте, исчез ли зомби: ps aux | grep 'Z'.

⚠️ Важно: Многие программы не имеют кастомного обработчика для SIGCHLD по умолчанию. В таком случае ядро просто игнорирует этот сигнал, и зомби останется.

Способ 2: Завершить родительский процесс

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

  1. Убедитесь, что PID родителя (PPID) корректен и вы готовы его завершить. Внимание: завершение системного процесса (например, sshd, cron) может привести к временной неработоспособности службы.
  2. Отправьте сигнал завершения:
    kill <PPID>
    
    Если процесс не реагирует, используйте принудительное завершение:
    kill -9 <PPID>
    
  3. После завершения родителя проверьте список процессов. Зомби должен исчезнуть.

Способ 3: Перезапуск родительского процесса (если это сервис)

Если родительский процесс — это системный демон (например, apache2, nginx, mysql), правильным решением будет его перезапуск через менеджер служб.

Для systemd:

sudo systemctl restart <имя_сервиса>

Для SysVinit (старые системы):

sudo service <имя_сервиса> restart

Перезапуск службы гарантирует, что новый экземпляр процесса-родителя начнёт корректно управлять своими дочерними процессами.

Способ 4: Отладка и исправление исходного кода (для разработчиков)

Если зомби-процессы постоянно появляются в вашем собственном приложении, необходимо исправить его код.

  1. Найдите в коде родительского процесса места после fork().
  2. Убедитесь, что сразу после fork() в родительской ветке есть вызов wait() или waitpid() для сбора статуса дочернего процесса.
  3. Если родитель должен работать параллельно с дочерним процессом, необходимо:
    • Установить обработчик сигнала SIGCHLD с помощью signal() или sigaction().
    • Внутри обработчика вызывать waitpid() в цикле (чтобы собрать всех завершившихся детей).
    • Или периодически (неблокирующим вызовом) проверять наличие завершившихся детей.

Пример корректного обработчика на C:

#include <sys/wait.h>
#include <signal.h>

void sigchld_handler(int s) {
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

// В main(): signal(SIGCHLD, sigchld_handler);

Профилактика

Чтобы избежать накопления зомби-процессов в будущем:

  1. Для системных администраторов: Регулярно проверяйте список процессов на наличие зомби (ps aux | grep 'Z'), особенно после запуска/останова критичных служб. Если зомби появляются из-за конкретного демона, ищите обновления для этого ПО или сообщайте баг разработчикам.
  2. Для разработчиков:
    • Всегда обрабатывайте сигнал SIGCHLD в родительских процессах, которые создают дочерние через fork().
    • Используйте неблокирующий вызов waitpid(-1, &status, WNOHANG) в цикле внутри обработчика, чтобы собрать всех завершившихся детей.
    • Рассмотрите возможность использования более высокоуровневых конструкций (например, subprocess в Python, который автоматически собирает статусы) вместо прямого fork/exec.
  3. Мониторинг: Настройте простой скрипт для мониторинга количества зомби-процессов и оповещения, если их число превышает, например, 10.
    #!/bin/bash
    ZOMBIE_COUNT=$(ps aux | grep -c ' Z ')
    if [ "$ZOMBIE_COUNT" -gt 10 ]; then
        echo "Внимание: обнаружено $ZOMBIE_COUNT зомби-процессов!" | wall
        # Можно также добавить отправку email или вызов pagerduty
    fi
    

Заключение

Зомби-процессы в Linux — это в основном следствие ошибок в родительских программах, а не критичная системная проблема. Они не потребляют значительных ресурсов, но их накопление указывает на некорректно работающий софт. В большинстве случаев достаточно завершить родительский процесс зомби, после чего ядро само очистит его запись. Для постоянного решения проблемы разработчикам необходимо исправлять код, а администраторам — следить за состоянием служб и обновлять ПО.

Часто задаваемые вопросы

Чем зомби-процесс отличается от сиротского (orphan)?
Могут ли зомби-процессы нагружать систему?
Как предотвратить появление зомби-процессов?
Почему команда kill -9 не работает на зомби?

Полезное

Определите зомби-процессы
Убедитесь, что родительский процесс существует
Отправьте сигнал SIGCHLD родителю
Завершите родительский процесс (осторожно)
Проверьте результат