Процесс-зомби (zombie process) — дочерний процесс в Unix-системе, завершивший своё выполнение, но ещё присутствующий в списке процессов операционной системы, чтобы дать родительскому процессу считать код завершения. Обычно, когда процесс завершает выполнение и работу, операционная система собирает статус завершения дочернего процесса с помощью системных вызовов wait() или waitpid(), выполненные родительским процессом. Если родительский процесс не вызывает эти функции вовремя, информация о состоянии дочернего процесса не может быть удалена из ядра, что приводит к тому, что процесс остается в состоянии "зомби". Попытка удалить зомби-процесс с помощью kill -9 неэффективна, поскольку он не занимает ресурсов CPU или памяти, а лишь сохраняет номер процесса (PID) и небольшое количество информации о состоянии.
Однако, если зомби-процессов становится слишком много, это может исчерпать ресурсы идентификаторов процессов, что помешает созданию новых процессов и негативно скажется на стабильности системы.
Причина появления процесс-зомби
Наиболее распространенная причина возникновения зомби-процесса:
Родительский процесс не успевает обработать информацию о завершении дочернего процесса, что приводит к его переходу в "зомби-состояние".
В этой статье будет рассмотрен пример на основе PostgreSQL.
Решение для состояния "t"
Когда главный процесс PostgreSQL находится в состоянии "t" (отслеживается и остановлен), можно использовать отладчик gdb
, чтобы удержать его. Если в этот момент убить дочерний процесс, он станет зомби-процессом.
Клиентские процессы, которые находятся в состоянии записи, также будут продолжать работу, в результате чего файлы WAL (Write Ahead Log) будут расти. В это время основное состояние процесса находится в состоянии “t”.
Чтобы восстановить нормальное состояние PostgreSQL, можно использовать команду:
ps -ef | grep 1797 # Для проверки процесса PostgreSQL
kill <PID> # Для завершения процесса
После этого дочерние процессы будут перезапущены, а состояние главного процесса вернется в "S".
Решение для состояния "t"
Состояние "t" указывает, что процесс остановлен. Чтобы исправить это, можно выполнить следующие действия:
Использовать
kill -19 <PID>
, чтобы остановить главный процесс.Затем завершить все дочерние процессы с помощью
kill -9
.
При этом состояние родительского процесса станет "t", и он не сможет обрабатывать сообщения о завершении дочернего процесса. Чтобы возобновить работу родительского процесса, можно отправить команду продолжения: kill -18 <PID>
Это позволит родительскому процессу снова начать обработку сигналов.
Когда процесс завершен, но родительский процесс еще не обработал его статус завершения, он становится зомби-процессом.
Важно отметить, что в вышеупомянутых состояниях дочерние процессы также могут находиться в состоянии "Z". Если состояние родительского процесса нормальное, но дочерний процесс "Z", то причины возникновения зомби-процесса становятся трудно отслеживаемыми.
Симуляция зомби-процесса
Для симуляции процесса, при котором родительский процесс не обрабатывает информацию о завершении дочернего процесса, можно создать скрипт zombie_process.py
со следующим содержимым:
import os
import time
def create_zombie():
pid = os.fork() # Создаем дочерний процесс
if pid > 0:
# Родительский процесс: не обрабатывает завершение дочернего процесса
print(f"Родительский процесс PID: {os.getpid()}")
print(f"Дочерний процесс PID: {pid}")
print("Дочерний процесс становится зомби (родитель не собирает статус).")
time.sleep(60) # Родительский процесс спит, чтобы сохранить дочерний процесс в состоянии зомби
elif pid == 0:
# Дочерний процесс
print(f"Дочерний процесс PID: {os.getpid()} завершен")
os._exit(0) # Завершаем дочерний процесс
if __name__ == "__main__":
create_zombie()
Запустите этот скрипт с помощью:
python3 zombie_process.py
В результате дочерний процесс будет находиться в состоянии "Z", а родительский процесс будет в нормальном состоянии. Чтобы избавиться от зомби-процесса, можно убить родительский процесс, чтобы управление перешло к системному процессу systemd
, который обработает статус завершения зомби-процесса.