Способы убить зомби-процессы
Какие ещё есть способы закапывания зомби-процессов, кроме убийства их родителей? Выдача гугла говорит, что убийство родителя — это самый простой способ, но какие есть способы более сложные? Киньте ссылку на годный материал о зомби-процессах, где разжёвываются все тонкости и нюансы работы с ними.
Нету тонкостей работы с зомби. Убить их нельзя, они уже мертвы.
Зомби-процесс это просто запись в таблице процессов. Таким образом ядро сохраняет pid и exit status «умершего» процесса, а нужно это для того, чтобы родитель мог получить exit status (код завершения) своего потомка. Пока родитель не спросит ядро код завершения потомка, в списке процессов будет зомби. Если родитель написан не правильно, то зомби и существуют пока существует родитель.
Это самое лучшее объяснение что я видел.
Спасибо тебе! 🙂
Разве зомби не сироты?
Root, please explain how to deal with processes in D state?
Ок, тогда можно ли как-нибудь защититься от переполнения таблицы процессов записями зомби? Без правки исходников родителя, разумеется.
Насколько я знаю, переполнение будет неизбежно. Можно поднять допустимое кол-во процессов, но это только увеличит время.
Если исходники родителя поправить нельзя, можно или поправить исходники ядра, или через LD_PRELOAD загрузить что-нибудь в родителя, допустим обёртку над exec(), которая бы делала не только exec(), но и wait().
D state == «Uninterruptible sleep». Ничего с ним сделать нельзя, когда процесс выйдет из этого состояния, он сразу получит все отправленные ему сигналы и, скорее всего, умрёт. Сделано это для корректной работы драйверов в ядре. Через системный вызов процесс выполнятся в режиме ядра, и может блочит ресурсы внутрия ядра (lock/unlock). Если он в этот момент завершится (exit()), то с ядреными блокировками может быть не всё в порядке, поэтому его и делают «неуявзвимым».
Вроде как сейчас в ядре вместоTASK_UNINTERRUPTIBLE может быть состояние процесса TASK_KILLABLE и если драйвер написан правильно, то он должен позволять убить (SIGKILL) процесс.
Если процесс ушёл в «D» при работе по NFS, то это так и задумано, иначе это бага драйвера или бага железа, не известная драйверу. По идее можно сделать
echo w > /proc/sysrq-trigger
и получить список процессов и системных вызовов, на которых они «заснули», чтобы бы понять куда слать баг-репорт.
Респект тебе, спасибо, объяснил. Не NFS, — тв-тюнер.
Вроде как сейчас в ядре вместоTASK_UNINTERRUPTIBLE может быть состояние процесса TASK_KILLABLE и если драйвер написан правильно, то он должен позволять убить (SIGKILL) процесс.
Мне всегда казалось, что D-state — просто костыль для говномодулеписателей, не могущих обработать блокировки в случае убиения процесса.
Мне всегда казалось, что D-state — просто костыль для говномодулеписателей, не могущих обработать блокировки в случае убиения процесса.
Тот же пример с тюнером: если почти одновременно запустить 2 tvtime, то второй завершится, а первый ничего не покажет, и будет вечно в D-state.
Ещё выдергивание вебкамеры у меня запросто оставляло mplayer в D-state
Отвал NFS, и винтов тоже часто приводит к тому же.
Анонимус пишет про убиение процесса, а вы приводите примеры ошибок в драйверах, когда без всяких sigkill всё плохо: «выдергивание вебкамеры у меня запросто оставляло mplayer в D-state». В случае кривого драйвера, зависание mplayer’а не в D-state ничем жизнь бы не улучшило. Ну получил бы mplayer сигнал, ну «умер» бы, драйвер то всё одно уже в неадекватном состоянии, явно бы от него остались в ядре не освобождённые ресурсы.
В случае с NFS так и задумано, D-state — это остановка процесса пока снова не появится связь с серером (с файловой системой). В остальных случаях, ИМХО, драйвер должен хотя бы по таймауту определять проблему с железом и завершать syscall с ошибкой. Если драйвер от проблем с железом впадает в кому, скорее всего в нём ошибка, или он просто не дописан (нет времени у автора или тестера).
Если я правильно понял, то TASK_KILLABLE полностью не отменяет TASK_UNINTERRUPTIBLE, в определённые моменты драйверу всё одно не нужны прерывания в виде sigkill, но при правльном подходе TASK_KILLABLE позволяет избежать длительного нахождения в TASK_UNINTERRUPTIBLE.
Источник
Зомби процессы в Linux
Пользователи устройств, функционирующих на операционной системе Linux, часто сталкиваются с таким распространенным явлением, как зомби процессы. На слух это название звучит весьма устрашающе, и с этим трудно поспорить, но на практике его бояться не стоит. Зомби процессы не способны нанести серьезный удар системе, хотя многие пользователи стараются удалять их во избежание каких-либо непредсказуемых проблем. Чтобы лучше понимать ситуацию, необходимо детальнее разобраться с тем, каким образом стандартный процесс превращается в зомби.
Функция fork запускает дочерний процесс, который попадает под контроль родительского процесса. Если родительский процесс получает сигнал о завершении дочернего процесса, но при этом игнорирует его (в возможные причины сбоя вдаваться не станем), то этот процесс становится зомби.
Стоит ли обращать на них своё внимание? Ответ: делать это совершенно не обязательно. Так как процесс уже был завершен, он перестал использовать системные ресурсы, но остался в системе. Самое разумное в этом случае – сделать вид, что его не существует, и продолжать работать с устройством, как ни в чем не бывало. Если пользователь попытается «уничтожить» зомби при помощи специальной команды «kill», у него ничего не выйдет, ведь этот процесс не выполняется. Это действие является бессмысленным, а потому процесс продолжит отображаться в системе.
Чтобы полностью убрать зомби, необходимо уничтожить или перезапустить его родительский процесс. Если есть такое желание, обратитесь к инструкции ниже.
Как посмотреть зомби в операционной системе Linux
Это можно сделать при помощи утилиты ps:
$ ps aux | grep defunct
Как обнаружить в системе «родителя»:
$ ps -xal | grep defunct
После того, как нашли родителя можно удалить зомби. Это единственный способ уничтожения зомби процесса. Прямые команды не удалят их. Найдите в колонке идентификатор «родителя». В приведенном примере он находится в 4-м столбце под номером 761.
С помощью команды «kill» пошлем сигнал завершения, чтобы зомби процесс прекратил своё существование в системе.
В вашем случае вместо 761 будет стоять другое значение. Его нужно правильно обнаружить.
Данные рекомендации созданы для тех пользователей, которые любят порядок во всем. Но еще раз напоминаем: зомби в операционной системе Линукс безвредны, и являются абсолютно логичным следствием ошибки.
Источник
Как убить процессы зомби в Linux
Плохо написанные или плохо работающие программы могут оставлять зомби-процессы, скрывающиеся внутри вашего Linux-компьютера. Узнайте, как создаются зомби и как их наконец упокоить.
Как состояния процесса работают в Linux
Linux, конечно же, должен отслеживать все приложения и демоны, работающие на вашем компьютере. Один из способов сделать это — поддерживать таблицу процессов. Это список структур в памяти ядра. Каждый процесс имеет запись в этом списке, которая содержит некоторую информацию о нем.
В каждой из структур таблицы процессов нет ничего особенного. Они держат идентификатор процесса, несколько других элементов данных и указатель на блок управления процессом (PCB) для этого процесса.
Это печатная плата, которая содержит множество деталей, которые Linux необходимо найти или настроить для каждого процесса. Плата также обновляется по мере создания процесса с учетом времени обработки и, наконец, уничтожается.
Печатная плата Linux содержит более 95 полей. Это определено как структура, называемая task_struct.h , и это более 700 строк. Печатная плата содержит следующие типы информации:
- Состояние процесса: Состояния описаны ниже.
- Номер процесса: Его уникальный идентификатор в операционной системе.
- Счетчик команд: Когда этому процессу в следующий раз будет предоставлен доступ к ЦП, система будет использовать этот адрес для поиска следующей инструкции процесса, который должен быть выполнен.
- Регистры: Список регистров ЦП, используемых этим процессом. Список может содержать аккумуляторы, индексные регистры и указатели стека.
- Открыть список файлов: Файлы, связанные с этим процессом.
- Информация о расписании ЦП: Используется для определения того, как часто и как долго процессорное время выделяется на этот процесс. Приоритет процесса, указатели на очереди планирования и другие параметры планирования должны быть записаны на плате.
- Информация об управлении памятью: Подробная информация о памяти, которую использует этот процесс, например, начальный и конечный адреса памяти процесса и указатели на страницы памяти.
- Информация о состоянии ввода / вывода: Любые устройства ввода или вывода, используемые процессом.
«Состояние процесса» может быть любым из следующих:
- Р: Работающий или готовый к выполнению процесс. Запуск означает, что он получает циклы ЦП и выполняется. Готовый к работе процесс готов к запуску и ждет слота ЦП.
- S: Спящий процесс. Процесс ожидает завершения действия, такого как операция ввода или вывода, или доступности ресурса.
- D: Процесс находится в состоянии непрерывного сна. Он использует блокирующий системный вызов и не может продолжать работу до завершения системных вызовов. В отличие от состояния «сна», процесс в этом состоянии не будет реагировать на сигналы до тех пор, пока системный вызов не завершится и выполнение не вернется к процессу.
- Т: Процесс завершен (остановлен), потому что он получил SIGSTOP сигнал. Это буду только отвечать к SIGKILL или SIGCONT сигналы, которые либо завершают процесс, либо предписывают ему продолжить, соответственно. Вот что происходит, когда вы меняете передний план ( fg ) к задний план ( bg) задачи.
- С УЧАСТИЕМ: Зомби-процесс. Когда процесс завершается, он не исчезает просто так. Он освобождает всю используемую память и удаляет себя из памяти, но его записи в таблице процессов и на плате остаются. Его состояние установлено на EXIT_ZOMBIE , и его родительский процесс уведомляется ( SIGCHLD signal) о завершении дочернего процесса.
В состоянии Zombie родительский процесс вызывает один из wait() семейства функций при создании дочернего процесса. Затем он ждет изменения состояния в дочернем процессе. Был ли дочерний процесс остановлен, продолжен или уничтожен сигналом? Завершилось ли оно естественным завершением своего кода?
Если изменение состояния означает, что дочерний процесс остановлен, считывается его код выхода. Затем дочерняя печатная плата уничтожается, а его запись в таблице процессов удаляется. В идеале все это происходит в мгновение ока, а процессы в состоянии зомби существуют не очень долго.
Что вызывает зомби-процессы в Linux?
Плохо написанный родительский процесс может не вызывать wait() функция при создании дочернего процесса. Это означает, что ничто не отслеживает изменения состояния в дочернем процессе, и SIGCHLD сигнал будет проигнорирован. Или, возможно, другое приложение влияет на выполнение родительского процесса из-за плохого программирования или злого умысла.
Однако, если родительский процесс не следит за изменениями состояния в дочернем процессе, надлежащего обслуживания системы не произойдет. Плата и запись в таблице процессов не будут удалены при завершении дочернего процесса. Это приводит к тому, что состояние зомби никогда не удаляется с печатной платы.
Зомби используют немного памяти, но обычно не представляют проблемы. Запись в таблице процессов небольшая, но, пока она не будет выпущена, идентификатор процесса нельзя использовать повторно. В 64-битной операционной системе это вряд ли вызовет какие-либо проблемы, потому что размер платы намного больше, чем запись в таблице процессов.
Возможно, огромное количество зомби может повлиять на объем памяти, свободной для других процессов. Однако, если у вас так много зомби, у вас серьезная проблема с родительским приложением или ошибка операционной системы.
Как удалить зомби-процессы
Вы не можете убить процесс зомби, потому что он уже мертв. Он не будет реагировать ни на какие сигналы, потому что был удален из памяти — некуда отправлять SIGKILL сигнал. Вы можете попробовать отправить SIGCHLD сигнал родительскому процессу, но если он не сработал при завершении дочернего процесса, вряд ли он сработает и сейчас.
Единственное надежное решение — убить родительский процесс. Когда он завершается, его дочерние процессы наследуются init процесс, который является первым процессом, который запускается в системе Linux (его идентификатор процесса равен 1).
В init process регулярно выполняет необходимую очистку от зомби, поэтому, чтобы убить их, вам просто нужно убить процесс, который их создал. В top command — удобный способ узнать, есть ли у вас зомби.
В этой системе восемь зомби-процессов. Мы могу перечислить эти используя ps команда и подключил его к egrep . Опять же, у зомби-процессов есть государственный флаг «Z», и вы обычно также видите «несуществующие».
Это более удобный способ узнать идентификаторы процессов зомби, чем прокрутка назад и вперед. top . Мы также видим, что этих зомби породило приложение под названием «badprg».
Идентификатор процесса первого зомби — 7641, но нам нужно найти идентификатор процесса его родительского процесса. Мы можем сделать это, используя ps еще раз. Мы будем использовать параметр вывода ( -o ) сказать ps чтобы отобразить только идентификатор родительского процесса, а затем передать его с ppid= флаг.
Процесс, который мы хотим найти, будет обозначен с помощью -p (process) вариант, а затем передать идентификатор процесса зомби.
Поэтому мы вводим следующую команду для поиска информации о процессе 7641, но она будет сообщать только идентификатор родительского процесса:
Нам сказали, что идентификатор родительского процесса — 7636. Теперь мы можем ссылаться на него, используя ps еще раз.
Мы видим, что это соответствует названию родительского процесса ранее. Чтобы убить родительский процесс, используйте параметр SIGKILL с командой kill следующим образом:
В зависимости от владельца родительского процесса вам также может потребоваться sudo .
Зомби не страшны…
… Если они не в огромной орде. О некоторых не стоит беспокоиться, и простая перезагрузка уничтожит их.
Однако, если вы заметили, что приложение или процесс всегда порождают зомби, вам следует изучить это. Скорее всего, это просто небрежно написанная программа, и в этом случае, возможно, есть обновленная версия, которая должным образом очищается после своих дочерних процессов.
Источник