Что такое зомби-процесс и опасен ли он?

Ответ

Зомби-процесс (или defunct process) — это дочерний процесс в Unix-подобных системах, который завершил своё выполнение, но всё ещё присутствует в таблице процессов операционной системы.

Почему он возникает?

Он "зависает" в этом состоянии, чтобы родительский процесс мог прочитать его код завершения (exit status) с помощью системного вызова wait(). Таким образом, зомби — это не ошибка, а штатный механизм обратной связи между дочерним и родительским процессами.

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

Опасность зомби-процессов:

  • Один зомби-процесс практически безвреден. Он не потребляет CPU и занимает очень мало памяти (только запись в таблице процессов).
  • Опасность возникает при их накоплении. Если программа постоянно создает дочерние процессы и не обрабатывает их завершение, таблица процессов может переполниться. Это приведёт к тому, что система не сможет запускать новые процессы.

Пример в Go, который может создать зомби:

package main

import (
    "os/exec"
    "time"
)

func main() {
    cmd := exec.Command("sleep", "1")
    _ = cmd.Start() // Запускаем процесс асинхронно

    // Родительский процесс не ждет завершения дочернего.
    // На 1 секунду процесс sleep станет зомби, пока родитель не завершится.
    time.Sleep(2 * time.Second)
}

Как избежать в Go:

  • Всегда вызывать cmd.Wait() после cmd.Start() для получения результата и освобождения ресурсов.
  • Использовать cmd.Run(), который внутри себя вызывает Start и Wait.

Ответ 18+ 🔞

А, слушай, вот эта тема про зомби-процессы — это же классика, блядь! Ну, как в старом хорроре: вроде и помер, а в таблице процессов ещё торчит, ёпта.

Короче, представь: процесс-ребёнок отработал своё, кончился, должен бы на свалку истории. Но нет, сука! Он как призрак остаётся в системе, в таблице процессов, и ждёт, пока папаша-процесс прочитает его предсмертную записку — код завершения. Это если по-нормальному, через wait(). Это штатная фича, а не глюк, понимаешь? Так и задумано, блядь.

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

Вот смотри, на Go как такого зомби сварганить можно, если очень постараться:

package main

import (
    "os/exec"
    "time"
)

func main() {
    cmd := exec.Command("sleep", "1")
    _ = cmd.Start() // Запустили и забыли, типа "лети, сынок!"

    // А сам родитель нихуя не ждёт. Спит себе.
    // На секундочку этот sleep станет зомби, пока мы не выйдем.
    time.Sleep(2 * time.Second)
}

Видал подвох? Start() есть, а Wait() — нету. Родитель-мудак даже не поинтересовался, как там его чадо. Вот оно и болтается неприкаянное.

Как не быть мудаком в Go:

  1. Всегда после cmd.Start() делай cmd.Wait(). Это как похоронить по-человечески, блядь. Узнал код выхода, ресурсы освободил — красота.
  2. Или вообще используй cmd.Run(). Это для ленивых, но умных. Он внутри сам и стартанёт, и подождёт, всё как надо. Никаких зомби, одна чистота, в рот меня чих-пых!

Вот и вся магия, нехуй тут сложного. Главное — не плоди сирот и не забывай про Wait(), а то система тебя самого как зомби запомнит, небось.