Ответ
Зомби-процесс (или 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:
- Всегда после
cmd.Start()делайcmd.Wait(). Это как похоронить по-человечески, блядь. Узнал код выхода, ресурсы освободил — красота. - Или вообще используй
cmd.Run(). Это для ленивых, но умных. Он внутри сам и стартанёт, и подождёт, всё как надо. Никаких зомби, одна чистота, в рот меня чих-пых!
Вот и вся магия, нехуй тут сложного. Главное — не плоди сирот и не забывай про Wait(), а то система тебя самого как зомби запомнит, небось.