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

<p>у меня есть процесс, который я не могу убить с помощью <code>kill -9 <pid></code>. в чем проблема в таком случае, тем более что я являюсь владельцем этого процесса. я думал, что ничто не сможет уклониться от этой опции <code>kill</code>.</p>

<p><code>kill -9</code> ( <a href="http://en.wikipedia.org/wiki/sigkill"> sigkill </a> ) всегда работает, если у вас есть разрешение на завершение процесса. по сути, либо процесс должен быть запущен вами, а не быть setuid или setgid, либо вы должны быть пользователем root. есть одно исключение: даже root не может отправить фатальный сигнал в pid 1 (процесс <code>init</code>).</p><p>однако <code>kill -9</code> не гарантируется работа <em> немедленно</em>. все сигналы, включая sigkill, доставляются асинхронно: ядру может потребоваться время для их доставки. обычно доставка сигнала занимает не более нескольких микросекунд, то есть времени, которое требуется для цели, чтобы получить интервал времени. однако, если цель имеет <a href="http://www.cis.temple.edu/~ingargio/cis307/readings/signals.html">заблокировала сигнал</a> , сигнал будет поставлен в очередь, пока цель не разблокирует его.</p><p>обычно процессы не могут блокировать sigkill. но код ядра может, и процессы выполняют код ядра, когда они вызывают <a href="http://en.wikipedia.org/wiki/system\_call">системные вызовы</a> . код ядра блокирует все сигналы, когда прерывание системного вызова может привести к неверно сформированной структуре данных где-то в ядре или, в более общем случае, к нарушению некоторого инварианта ядра. таким образом, если (из-за ошибки или неправильной конструкции) системный вызов блокируется на неопределенный срок, фактически не может быть способа уничтожить процесс. (но процесс <em> будет</em> будет убит, если он когда-либо завершит системный вызов.)</p><p>процесс, заблокированный в системном вызове, находится в <a href="http://en.wikipedia.org/wiki/sleep\_%28operating\_system%29#uninterruptible\_sleep">непрерывный сон</a> . команда <code>ps</code> или <code>top</code> (в большинстве случаев) покажет ее в состоянии <code>d</code> (изначально для "<strong> d </strong> isk") , я думаю).</p><p>классический случай длительного непрерывного сна - это процессы, обращающиеся к файлам через <a href="http://en.wikipedia.org/wiki/network\_file\_system\_%28protocol%29"> nfs </a> , когда сервер не отвечает; современные реализации, как правило, не навязывают непрерывный сон (например, в linux опция монтирования <code>intr</code> позволяет сигналу прерывать доступ к файлу nfs).</p><p>иногда вы можете увидеть записи, помеченные <code>z</code> (или <code>h</code> в linux, я не знаю, в чем отличие) в выходных данных <code>ps</code> или <code>top</code>. технически это не процессы, это процессы-зомби, которые представляют собой не что иное, как запись в таблице процессов, которая хранится так, чтобы родительский процесс мог быть уведомлен о смерти своего потомка. они исчезнут, когда родительский процесс <a href="http://pubs.opengroup.org/onlinepubs/009695399/functions/wait.html">обращает внимание</a> (или умрет).</p>

<p>иногда процесс существует и не может быть остановлен из-за:</p><ul> <li>быть зомби. то есть процесс, родитель которого не прочитал статус выхода. такой процесс не потребляет никаких ресурсов, кроме ввода pid. в <code>top</code> указано z</li> <li>ошибочный непрерывный сон. это не должно происходить, но с комбинацией с ошибочным кодом ядра и/или с ошибочным оборудованием, которое иногда случается. единственный способ - перезагрузиться или подождать. в <code>top</code> это сигнализируется d.</li> </ul>

<p>похоже, у вас может быть <a href="http://en.wikipedia.org/wiki/zombie\_process">процесс зомби</a> . это безвредно: единственный ресурс, который потребляет зомби-процесс, - это запись в таблице процессов. он исчезнет, когда родительский процесс умрет или отреагирует на смерть своего ребенка.</p><p>вы можете увидеть, является ли процесс зомби, используя <code>top</code> или следующую команду:</p><pre><code>ps aux | awk '$8=="z" {print $2}' </code></pre>

<p>проверьте свои <code>/var/log/kern.log</code> а также <code>/var/log/dmesg</code> (или эквиваленты) для любых подсказок. по моему опыту, это случилось со мной, только когда внезапно оборвалось сетевое соединение монтирования nfs или произошел сбой драйвера устройства. я думаю, это может произойти и в случае сбоя жесткого диска.</p><p>вы можете использовать <code>lsof</code>, чтобы увидеть, какие файлы устройств открыт у процесса.</p>

<p>если ответы @ <a href="https://unix.stackexchange.com/questions/5642/what-if-kill-9-doesnt-work/5647#5647">maciej</a> и @ <a href="https://unix.stackexchange.com/questions/5642/what-if-kill-9-doesnt-work/5648#5648">gilles</a> не решают вашу проблему, и вы не распознаете процесс (и спрашиваете, что это с вашим дистрибутивом, не не включай ответы). проверьте наличие руткитов и любых других признаков того, что вы <em> принадлежали </em>. руткит более чем способен помешать вам убить процесс. на самом деле многие способны помешать вам увидеть их. но если они забудут изменить одну маленькую программу, они могут быть замечены (например, они изменили <code>top</code>, но не <code>htop</code>). скорее всего, это не так, но лучше, чем потом сожалеть.</p>

<p>убить на самом деле означает отправить сигнал. есть несколько сигналов, которые вы можете отправить. убить -9 это особый сигнал.</p><p>при отправке сигнала приложение имеет дело с ним. если не ядро имеет дело с этим. так что вы можете перехватить сигнал в вашем приложении.</p><p>но я сказал, что kill -9 был особенным. особенность в том, что приложение не получает его. это идет прямо к ядру, которое тогда действительно убивает приложение при первой возможности. другими словами убивает его мертвым</p><p>kill -15 отправляет сигнал sigterm, который означает signal terminate, другими словами, указывает приложению выйти. это удобный способ сообщить приложению, что пора завершать работу. но если приложение не отвечает, kill -9 убьет его.</p><p>если kill -9 не работает, это, вероятно, означает, что ваше ядро вышло из строя. перезагрузка в порядке. я не могу вспомнить, что когда-либо происходило.</p>

<p>во-первых, проверьте, если это процесс zombie (что очень возможно):</p><pre><code>ps -al </code></pre><p>вы увидите что-то вроде:</p><pre><code>0 z 1000 24589 1 0 80 0 - 0 exit ? 00:00:00 soffice.bin <defunct> </code></pre><p>(обратите внимание на "z" слева)</p><p>если 5-й столбец не 1, это означает, что у него есть родительский процесс. <strong>попробуйте убить этот идентификатор родительского процесса</strong>.</p><p>если его ppid = 1, <strong>не убивайте это !!</strong>, подумайте, какие другие устройства или процессы могут быть связаны с ним.</p><p>например, если вы использовали подключенное устройство или samba, попробуйте отключить его. это может освободить процесс зомби.</p><p><strong> примечание </strong>: если <code>ps -al</code> (или <code>top</code>) показывает "d" вместо "z", это может быть связано с удаленным монтированием (например, nfs). по моему опыту, перезагрузка - единственный путь туда, но вы можете проверить другие ответы, которые покрывают этот случай более подробно.</p>

<p>процесс init невосприимчив к sigkill.</p><p>это также верно для потоков ядра, то есть "процессов" с ppid, равным 0.</p>

<p>как уже упоминали другие, процесс в непрерывном сне не может быть немедленно прекращен (или, в некоторых случаях, вообще). стоит отметить, что было добавлено другое состояние процесса, task\_killable, для решения этой проблемы в определенных сценариях, особенно в частом случае, когда процесс ожидает в nfs. смотрите <a href="http://lwn.net/articles/288056/">http://lwn.net/articles/288056/</a> </p><p>к сожалению, я не верю, что это используется где-либо в ядре, кроме nfs.</p>

<p>сделал небольшой сценарий, который мне очень помог взглянуть!</p><p>вы можете использовать его для уничтожения любого процесса с заданным именем в своем пути (обратите внимание на это !!) или вы можете уничтожить любой процесс данного пользователя с помощью параметра -u username.</p><pre class="lang-bash prettyprint-override"><code>#!/bin/bash if [ "$1" == "-u" ] ; thenn 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 </code></pre>

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

<p>от <a href="https://www.redhat.com/archives/rhl-list/2004-january/msg04426.html">здесь изначально</a> :</p><p>проверьте, показывает ли что-нибудь strace</p><pre><code>strace -p <pid> </code></pre><p>попробуйте присоединиться к процессу с помощью gdb</p><pre><code>gdb <path to binary> <pid> </code></pre><p>если процесс взаимодействовал с устройством, которое вы можете размонтировать, удалить модуль ядра или физически отключить/отключить ... попробуйте это.</p>

<p>у меня была такая проблема. это была программа, которую я запустил с помощью <code>strace</code> и прервал с помощью <code>ctrl</code> + <code>c</code>. он оказался в состоянии <code>t</code> (отслежено или остановлено). я не знаю, как именно это произошло, но с <code>sigkill</code> это невозможно было убить.</p><p>короче говоря, мне удалось убить его с помощью <code>gdb</code>:</p><pre><code>gdb -p <pid> > kill kill the program being debugged? (y or n) y > quit </code></pre>

<p>основываясь на подсказке из ответа жиля, у меня был процесс, помеченный "z" ("" в ps), который использовал системные ресурсы, у него даже был открыт порт, который слушал, и вы могли подключиться к нему. это было после выполнения <code>kill -9</code> в теме. его родитель был "1" (то есть <code>init</code>), поэтому теоретически он должен просто исчезнуть. но это было не так, он торчал, хотя и не бежал.</p><p>так что в моем случае это был зомби, но все же потребляющий ресурсы ... fwiw.</p><p>и это не было убито <code>kill -9</code>.</p><p>и его родителем был <code>init</code>, но он не был собран (очищен). то есть <code>init</code> был ребенок-зомби.</p><p>и перезагрузка не была необходима, чтобы исправить проблему. хотя перезагрузка "сработала бы" вокруг проблемы/сделала бы ее более быстрым отключением. просто не изящно, что все еще было возможно.</p><p>и это был порт listen, принадлежащий процессу зомби (и несколько других портов, например, статус close\_wait, подключали localhost к localhost). и это все еще даже приняли связи. даже как зомби. я предполагаю, что еще не удавалось очистить порты, поэтому входящие соединения все еще добавлялись в журнал ожидания порта прослушивания tcp, хотя у них не было никаких шансов быть принятым.</p><p>оказывается, у меня был внутренний поток внутри него, который выполнял "системный вызов" (в данном случае ioctl), который возвращался через несколько часов (это ожидалось). очевидно, что система не может убить его "полностью", пока он не вернется из этого. через несколько часов все прояснилось, и все розетки были автоматически закрыты и т.д., как и ожидалось. это какое-то томительное время смерти!</p><p>также проверьте dmesg, чтобы увидеть, была ли паника ядра (то есть ошибка ядра).</p>