Что делать, если «kill -9» не работает?

466

У меня есть процесс, с которым я не могу убить kill -9 <pid>. В чем проблема в таком случае, тем более что я являюсь владельцем этого процесса. Я думал, что ничто не может избежать этого killварианта.

tshepang
источник

Ответы:

560

kill -9( SIGKILL ) всегда работает, если у вас есть разрешение убить процесс. По сути, либо процесс должен быть запущен вами, а не быть setuid или setgid, либо вы должны быть пользователем root. Есть одно исключение: даже root не может отправить фатальный сигнал в PID 1 ( initпроцесс).

Однако kill -9не гарантируется, что работать сразу . Все сигналы, включая SIGKILL, доставляются асинхронно: ядру может потребоваться время для их доставки. Обычно доставка сигнала занимает не более нескольких микросекунд, то есть времени, которое требуется для цели, чтобы получить интервал времени. Однако, если цель заблокировала сигнал , сигнал будет поставлен в очередь, пока цель не разблокирует его.

Обычно процессы не могут блокировать SIGKILL. Но код ядра может, и процессы выполняют код ядра, когда они вызывают системные вызовы . Код ядра блокирует все сигналы, когда прерывание системного вызова может привести к неверно сформированной структуре данных где-то в ядре или, в более общем случае, к нарушению некоторого инварианта ядра. Таким образом, если (из-за ошибки или неправильного проектирования) системный вызов блокируется на неопределенный срок, фактически не может быть способа уничтожить процесс. (Но процесс будет остановлен, если он когда-либо завершит системный вызов.)

Процесс, заблокированный в системном вызове, находится в непрерывном режиме сна . Команда psor top(в большинстве устройств) покажет его в состоянии D( я думаю, изначально для « d isk»).

Классический случай длительного непрерывного сна - это процессы, которые обращаются к файлам по NFS, когда сервер не отвечает; современные реализации, как правило, не навязывают непрерывный сон (например, в Linux intrопция монтирования позволяет сигналу прерывать доступ к файлам NFS).

Иногда вы можете увидеть записи, помеченные Z(или Hв Linux, я не знаю, что это за различие) в выводе psили top. Технически это не процессы, это процессы-зомби, которые представляют собой не что иное, как запись в таблице процессов, которая хранится так, чтобы родительский процесс мог быть уведомлен о смерти своего потомка. Они исчезнут, когда родительский процесс обратит внимание (или умрет).

жилль
источник
92
Ваш ответ выглядит противоречивым. Вы начинаете говорить, что SIGKILL всегда работает, но заканчиваете ссылками на бесперебойный спящий случай, когда SIGKILL может никогда не работать вне, выключая ядро. Есть также два случая, когда SIGKILL не работает. Очевидно, что с зомби нельзя убить уже мертвые процессы, а с помощью init, который по своей конструкции игнорирует сигналы SIGKILL.
jlliagre
41
@jlliagre: Убивать зомби не имеет смысла, оно не живое с самого начала. И убить процесс в прерываемом сне делает работу, это просто (как и с другими сигналами) асинхронными. Я попытался уточнить это в моем редактировании.
Жиль
3
Я тоже писал, что убивать зомби не имеет смысла, но это не мешает многим людям пробовать это и жаловаться. Уничтожение процесса в режиме прерывистого сна действительно работает по замыслу, но я говорил об отключении процесса в режиме непрерывного сна, который может завершиться неудачей, если системный вызов никогда не проснется.
Jlliagre
11
man 5 nfs: «Параметр intr/ nointrmount устарел после ядра 2.6.25. Только SIGKILL может прервать ожидающую операцию NFS на этих ядрах, и, если указано, этот параметр монтирования игнорируется для обеспечения обратной совместимости со старыми ядрами».
Мартин Шредер
4
@ imz - IvanZakharyaschev Не то, что я знаю (но я, возможно, не знаю). С помощью sshfs, в крайнем случае, вы можете убить sshfsпроцесс (и аналогично с любой другой файловой системой FUSE: вы всегда можете принудительно размонтировать этот путь).
Жиль
100

Иногда процесс существует и не может быть остановлен из-за:

  • быть зомби Т.е. процесс, родитель которого не прочитал статус выхода. Такой процесс не потребляет никаких ресурсов, кроме ввода PID. В topэто сигнализируется Z
  • ошибочный непрерывный сон. Это не должно происходить, но с комбинацией с ошибочным кодом ядра и / или с ошибочным оборудованием, которое иногда случается. Единственный способ - перезагрузиться или подождать. На topэто сигнализирует Д.
Мацей Печотка
источник
2
Зомби не потребляет ресурсы?
Люк М
7
@Luc M: AFAIK no (по крайней мере, в Linux) - за исключением записи в таблице процессов (т. Е. PID вместе с такой информацией, как владелец, состояние выхода и т. Д.). Это просто процесс, который ожидает подтверждения от partent, что он завершился.
Мацей Пехотка
18
@xenoterracide: В конце концов, да, но если родительский процесс все еще жив (например, это сеанс gnome или что-то, что выполняет аналогичную роль), у вас все еще могут быть зомби. Технически, это чистка работы родителей, но если зомби осиротели, init чистит после него (терминология является причиной, по которой классы unix делаются с закрытыми дверями - любой, кто слышит о сиротах, зомби и убийствах в одном предложении, может иметь неправильные впечатления).
Мацей Пехотка
5
«... единственный способ - это перезагрузить компьютер или подождать.» Подождите, как долго? Прошло пять месяцев, а мои зомби все еще там.
DarenW
3
@DarenW, пока родитель не признает смерть детей. За подробностями обращайтесь к автору программы.
Мацей Пехотка
32

Похоже, у вас может быть процесс зомби . Это безвредно: единственный ресурс, который потребляет зомби-процесс, - это запись в таблице процессов. Он исчезнет, ​​когда родительский процесс умрет или отреагирует на смерть своего ребенка.

Вы можете увидеть, является ли процесс зомби, используя topили следующую команду:

ps aux | awk '$8=="Z" {print $2}'
мистифицировать
источник
14
Хм, мне всегда не нравятся такие «жесткие» имена полей ps. Кто может быть уверен, что обязательное поле всегда будет восьмым со всеми реализациями psво всех Unices?
syntaxerror
26

Проверьте ваши /var/log/kern.logи /var/log/dmesg(или их эквиваленты) на наличие улик. По моему опыту, это случилось со мной, только когда внезапно оборвалось сетевое соединение монтирования NFS или произошел сбой драйвера устройства. Я думаю, это может произойти и в случае сбоя жесткого диска.

Вы можете использовать, lsofчтобы увидеть, какие файлы устройства открыт процесс.

LawrenceC
источник
6
+1 за упоминание NFS. Несколько лет назад это случалось со мной каждые пару месяцев - в случае сбоя сервера NFS клиенты NFS на всех (исправленных) коробках RHEL зависали. kill -9обычно не работает, даже после ожидания 60 минут. Единственным решением была перезагрузка.
Стефан Ласевский
17

Если ответы @ Maciej и @ Gilles не решают вашу проблему, и вы не распознаете процесс (а вопрос о том, что происходит с вашим дистрибутивом, не приводит к ответам). Проверьте , руткитов и любые другие признаки того, что вы были в собственности . Руткит более чем способен помешать вам убить процесс. На самом деле многие способны помешать вам увидеть их. Но если они забывают изменить одну маленькую программу, они могут быть обнаружены (например, они изменили top, но не сделали htop). Скорее всего, это не так, но лучше, чем потом сожалеть.

xenoterracide
источник
Я предполагаю, что многие руткиты вставляются в ядро, чтобы упростить задачу (не нужно угадывать, что у пользователя есть, и загружать МБ исправленных программ). Однако это все еще стоит проверить (голосование ++).
Мацей Печотка
11

Убить на самом деле означает отправить сигнал. Есть несколько сигналов, которые вы можете отправить. убить -9 это особый сигнал.

При отправке сигнала приложение имеет дело с ним. если не ядро ​​имеет дело с этим. так что вы можете перехватить сигнал в вашем приложении.

Но я сказал, что kill -9 был особенным. Особенность в том, что приложение не получает его. это идет прямо к ядру, которое тогда действительно убивает приложение при первой возможности. другими словами убивает его мертвым

kill -15 отправляет сигнал SIGTERM, который означает TIGNINATE TIGNINATE, другими словами, указывает приложению выйти. Это удобный способ сообщить приложению, что пора завершать работу. но если приложение не отвечает, kill -9 убьет его.

если kill -9 не работает, это, вероятно, означает, что ваше ядро ​​вышло из строя. перезагрузка в порядке. Я не могу вспомнить, что когда-либо происходило.

DeveloperChris
источник
5
15 - SIGTERM (дружественное убийство), а не SIGHUP. SIGHUP предназначен для закрытия управляющего терминала или потери канала связи
JoelFan
11

Во-первых, проверьте, если это процесс Zombie (что очень возможно):

ps -Al

Вы увидите что-то вроде:

0 Z  1000 24589     1  0  80   0 -     0 exit   ?        00:00:00 soffice.bin <defunct>

(Обратите внимание на «Z» слева)

Если 5-й столбец не 1, это означает, что у него есть родительский процесс. Попробуйте убить этот родительский идентификатор процесса .

Если его PPID = 1, не убивайте его! Подумайте, какие другие устройства или процессы могут быть связаны с ним.

Например, если вы использовали подключенное устройство или самбу, попробуйте отключить его. Это может освободить процесс зомби.

ПРИМЕЧАНИЕ . Если ps -Al(или top) показывает «D» вместо «Z», это может быть связано с удаленным подключением (например, NFS). По моему опыту, перезагрузка - единственный путь туда, но вы можете проверить другие ответы, которые покрывают этот случай более подробно.

Лепе
источник
1
Отправка SIGCHLD родительскому процессу может привести к тому, что родитель узнает, что процесс умер. Это должно работать даже тогда, когда PPID = 1. Обычно оно отправляется ядром, но также может быть отправлено родителю через kill (kill -17 в Linux, проверьте man-страницы в других * nix). Такое использование kill на самом деле не «убивает» родителя, а скорее (повторно) информирует его о том, что ребенок умер и нуждается в очистке. Обратите внимание, что sigchld должен быть отправлен родителю зомби, а не самому зомби.
Стефани
10

Процесс init невосприимчив к SIGKILL.

Это также верно и для потоков ядра, то есть для «процессов» с PPID, равным 0.

jlliagre
источник
1
Задачи ядра также могут быть невосприимчивы к SIGKILL. Это происходит достаточно часто с Btrfs.
Тобу
9

Как уже упоминалось, процесс в непрерывном сне не может быть немедленно прекращен (или, в некоторых случаях, вообще). Стоит отметить, что было добавлено другое состояние процесса, TASK_KILLABLE, для решения этой проблемы в определенных сценариях, особенно в частом случае, когда процесс ожидает в NFS. Смотрите http://lwn.net/Articles/288056/

К сожалению, я не верю, что это используется где-либо в ядре, кроме NFS.


источник
У меня были проблемы с завершением lsпроцесса доступа к sshfsмонтированию, когда удаленный сервер стал недоступным. Есть ли решение для FUSE или sshfs, которое я мог бы использовать в будущем, чтобы избежать подобных ситуаций? 2.6.30 ядро
imz - Иван Захарящев
@imz Есть совет от Жиля (убить sshfs) - unix.stackexchange.com/a/5648/4319 .
imz - Иван Захарящев
6

Сделал небольшой сценарий, который мне очень помог взглянуть!

Вы можете использовать его для уничтожения любого процесса с заданным именем в своем пути (обратите внимание на это !!) Или вы можете уничтожить любой процесс данного пользователя с помощью параметра -u username.

#!/bin/bash

if [ "$1" == "-u" ] ; then\n
        PID=`grep "$2" /etc/passwd | cut -d ":" -f3`
        processes=`ps aux | grep "$PID" | egrep -v "PID|ps \-au|killbyname|grep" | awk '{ print $2}'`
        echo "############# Killing all processes of user: $2 ############################"
else
        echo "############# Killing processes by name: $1 ############################"
        processes=`ps aux | grep "$1" | egrep -v "killbyname|grep" | awk '{ print $2}' `
fi


for process in $processes ; do
        # "command" stores the entire commandline of the process that will be killed
        #it may be useful to show it but in some cases it is counter-productive
        #command=`ps aux | grep $process | egrep -v "grep" | awk '{ print $2 }'`
        echo "Killing process: $process"
        echo ""
        kill -9 $process
done
user36035
источник
4
Вместо того, чтобы просто ссылаться на него, вы можете разместить код здесь.
Чепанг
3
Добавьте немного описания с (или хотя бы взамен) кодом ...
vonbrand
Да, но "$ name" более агрегирует ... он убьет любой процесс с "$ name" в его рабочем пути. Может быть очень полезно, когда у вас есть эти огромные командные строки, и вы не знаете, как называется процесс.
user36035
5

Существуют случаи, когда даже если вы отправляете kill -9 процессу, этот pid останавливается, но процесс перезапускается автоматически (например, если вы попробуете его gnome-panel, он будет перезапущен): может ли это быть здесь?

dag729
источник
8
Когда что-то подобное происходит, PID фактически меняется. Так что я бы заметил.
Чепанг
2

из здесь изначально :

проверьте, показывает ли что-нибудь strace

strace -p <PID>

попробуйте присоединиться к процессу с помощью GDB

gdb <path to binary> <PID>

если процесс взаимодействовал с устройством, которое вы можете размонтировать, удалить модуль ядра или физически отключить / отключить ... попробуйте это.

nmz787
источник
Работал на меня! (отключив USB-устройство, на котором висел возвышенный текст)
nmz787
1

У меня была такая проблема. Это была программа, которую я запустил straceи прервал с помощью Ctrl+ C. Это закончилось в T(отслеженном или остановленном) состоянии. Я не знаю, как именно это произошло, но это не было убийственно SIGKILL.

Короче говоря, мне удалось убить его gdb:

gdb -p <PID>
> kill
Kill the program being debugged? (y or n) y
> quit
Кристоф Древет-Дроге
источник
-1

Основываясь на подсказке из ответа Жиля, у меня был процесс с пометкой «Z» вверху ( <defunct>в пс), который использовал системные ресурсы, у него даже был открыт порт, который СЛУШАЛ, и вы могли подключиться к этому порту. Это было после выполнения kill -9на нем. Его родитель был "1" (то есть init), так что теоретически его следует просто повторить и исчезнуть. Но это было не так, это продолжалось, хотя и не бегало, и «не умирал»

Так что в моем случае это был зомби, но все же потребляющий ресурсы ... FWIW.

И это было не Killable любого числа kill -9

И его родитель был, initно его не пожинали (убирали). Т.е. initбыл ребенок зомби.

И перезагрузка не была необходима, чтобы исправить проблему. Хотя перезагрузка "сработала бы" вокруг проблемы / сделала бы ее более быстрым отключением. Просто не изящно, что все еще было возможно.

И это был порт LISTEN, принадлежащий процессу зомби (и несколько других портов, например, статус CLOSE_WAIT, подключали localhost к localhost). И это все еще даже приняли связи. Даже как зомби. Я предполагаю, что еще не удавалось очистить порты, поэтому входящие соединения все еще добавлялись в журнал ожидания порта прослушивания tcp, хотя у них не было никаких шансов быть принятым.

Многие из вышеперечисленных заявлены как «невозможные» в различных местах в паутинах.

Оказывается, у меня был внутренний поток внутри него, который выполнял «системный вызов» (в данном случае ioctl), который возвращался через несколько часов (это было ожидаемое поведение). Очевидно, что система не может завершить процесс "полностью", пока он не вернется из ioctlвызова, предположим, что он входит в землю ядра. Через несколько часов он вернулся, все прояснилось, и все розетки были автоматически закрыты и т. Д., Как и ожидалось. Это какое-то томительное время в камере смертников! Ядро терпеливо ждали, чтобы убить его.

Поэтому, чтобы ответить на ОП, иногда приходится ждать. Долго. Тогда убийство, наконец, возьмет.

Также проверьте dmesg, чтобы увидеть, была ли паника ядра (то есть ошибка ядра).

rogerdpack
источник
Похоже, вы описываете свой собственный конкретный сценарий, а не ответ на вопрос. В вашем случае процесс исправился сам по себе из-за длительной работы, чего-то не упомянутого в вопросе. Однако вы можете задать новый вопрос и дать ответ на него. Хотя я боюсь, что этот вопрос может быть закрыт как «не воспроизводимый», поскольку результат зависит от вашей реализации.
Сентиман
Правда, я добавил, как он отвечает на OP, поскольку в некоторых случаях он мог.
rogerdpack