In your head, in your head, Zombie, zombie, zombie-ie-ie…

Привет. Вчера Юра в комментах спросил за зомби процессы и как с ними деликатно обходиться. Расскажу про свой не деликатный опыт. Поехали.

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

Всё, с теорией хватит. Чтобы потыкать палкой какой-нибудь зомби процесс, нужно его искусственно создать. Пишем на СИ портянку (ниже будет и на Bash):

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t child_pid;
    child_pid = fork();

    if (child_pid > 0) {
        sleep(7200);
    } else if (child_pid == 0) {
        printf("Дочерний процесс выполнен.\n");
        exit(0);
    } else {
        perror("Ошибка при вызове fork");
        exit(EXIT_FAILURE);
    }
    return 0;
}
Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Этот код создает дочерний процесс, который сразу же завершается. Родительский процесс ждет 2 часа и затем завершается без вызова wait(). Вот так мы и получим своего маленького зомби, над которым будем ставить эксперименты.

Компилируем и запускаем в фоне этого зомбаря:

gcc zombie.c -o zombie
./zombie &

Либо создаем зомби через Bash:

(sleep 1 & exec /bin/sleep 7200) &

Выполняем команды и наблюдаем zombie процесс:

ps aux | grep Z

Вывод на экран:

root 1669051 Z 14:09 0:00 [zombie] <defunct>

Ага, хорошо, зомби завели. Теперь как это дело всё закилить. Простой kill -9 PID не поможет, так как PID родительского процесса будет отличаться от дочернего.

Чтобы найти PID родителя, смотрим:

ps ax | grep zombie

Кто-то грепает по слову defunct, тут уже по потребностям выбирай.

Видим все PIDы и родителя и дочернего:

1669050 S+ 0:00 ./zombie
1669051 Z+ 0:00 [zombie] <defunct>

В моем случае PID родительского = 1669050, а дочернего 1669051, который собственно и есть зомбик.

Теперь накидываем однострочник:

kill -9 $(ps -A -o stat,ppid | grep -e '[zZ]'| awk '{ print $2 }')

Эта штука найдет все зомби процессы и уничтожит их. Даже не нужно никакие циклы на Bash колхозить.

А если требуется регулярно зачищать зомборей, вешаем однострочник на cron и радуемся.

Вообще это самый простой способ закилить эту каку. Как это сделать через gdb напишу на следующей неделе. Но сразу предупреждаю, там оверхед решение и скорее всего оно тебе не понравится. Хотя через gdb можно оставить в живых родительский процесс и убить только дочерних зомбаков.

У меня зомбаки порой случались с nginx на древней CentOS, но после апгрейда на убунту, все прошло.

Если сможешь что-то еще добавить, пиши в комменты, будет всем полезно.

Давай, хороших выходных, не болей!