Как найти зомби-процесс?

System information as of Fri Mar  9 19:40:01 KST 2012

  System load:    0.59               Processes:           167
  Usage of /home: 23.0% of 11.00GB   Users logged in:     1
  Swap usage:     0%                 IP address for eth1: 192.168.0.1

  => There is 1 zombie process.

  Graph this data and manage this system at https://landscape.canonical.com/

10 packages can be updated.
4 updates are security updates.

Last login: Fri Mar  9 10:23:48 2012
a@SERVER:~$ ps auxwww | grep 'Z'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
usera     13572  0.0  0.0   7628   992 pts/2    S+   19:40   0:00 grep --color=auto Z
a@SERVER:~$ 

Как найти этот процесс зомби?

9 ответов

Решение

Чтобы убить зомби (процесс), вы должны убить его родительский процесс (как настоящие зомби!), Но вопрос был в том, как его найти.

Найди зомби (на вопрос ответила эта часть):

a@SERVER:~$ ps aux | grep 'Z'

То, что вы получите, это Zombies и все остальное с Z в нем, так что вы также получите grep:

USER       PID     %CPU %MEM  VSZ    RSS TTY      STAT START   TIME COMMAND
usera      13572   0.0  0.0   7628   992 pts/2    S+   19:40   0:00 grep --color=auto Z
usera      93572   0.0  0.0   0      0   ??       Z    19:40   0:00 something

Найдите родителя зомби:

a@SERVER:~$ pstree -p -s 93572

Дам тебе:

init(1)---cnid_metad(1311)---cnid_dbd(5145)

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

Дополнительные ресурсы по Askubuntu:

Хотя этот вопрос старый, я думал, что все заслуживают более надежного ответа:

ps axo pid=,stat=

Это создаст два столбца, разделенных пробелами, первый из которых - PID, а второй - его состояние.

Я не думаю, что даже GNU ps предоставляет возможность фильтрации по состоянию напрямую, но вы можете надежно сделать это с awk

ps axo pid=,stat= | awk '$2~/^Z/ { print }'

Теперь у вас есть список PID, которые являются зомби. Поскольку вы знаете состояние, его больше не нужно отображать, чтобы его можно было отфильтровать.

ps axo pid=,stat= | awk '$2~/^Z/ { print $1 }'

Предоставление списка разделенных новой строкой PID зомби.

Теперь вы можете работать с этим списком с помощью простого цикла оболочки

for pid in $(ps axo pid=,stat= | awk '$2~/^Z/ { print $1 }') ; do
    echo "$pid" # do something interesting here
done

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

Меньше значит больше, хотя:

ps afuwwx | less +u -p'^(\S+\s+){7}Z.*'

Это как, дать мне лес (дерево) всех пользовательских процессов в ориентированном на пользователя формате с неограниченной шириной для любого tty и показать его мне на половине экрана выше, где это соответствует случаю, когда 8-й столбец содержит Z, и почему бы не выделить всю строку.

Пользовательский формат, кажется, означает:USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND поэтому статус зомби будет отображаться в 8-м столбце.

Вы можете бросить в N перед p если вы хотите, чтобы номера строк, и J если вы хотите звездочку на матче. К сожалению, если вы используете G не выделять строку, которую звездочка не покажет, хотя J создает пространство для этого.

В итоге вы получаете что-то похожее на:

…
  root      2919  0.0  0.0  61432  5852 ?      Ss Jan24 0:00 /usr/sbin/sshd -D
  root     12984  0.0  0.1 154796 15708 ?      Ss 20:20 0:00  \_ sshd: lamblin [priv]
  lamblin  13084  0.0  0.0 154796  9764 ?      S  20:20 0:00      \_ sshd: lamblin@pts/0
* lamblin  13086  0.0  0.0  13080  5056 pts/0  Z  20:20 0:00          \_ -bash <defunct>
  lamblin  13085  0.0  0.0  13080  5056 pts/0  Ss 20:20 0:00          \_ -bash
  root     13159  0.0  0.0 111740  6276 pts/0  S  20:20 0:00              \_ su - nilbmal
  nilbmal  13161  0.2  0.0  13156  5004 pts/0  S  20:20 0:00                  \_ -su
  nilbmal  13271  0.0  0.0  28152  3332 pts/0  R+ 20:20 0:00                      \_ ps afuwwx
  nilbmal  13275  0.0  0.0   8404   848 pts/0  S+ 20:20 0:00                      \_ less +u -Jp^(\S+\s+){7}Z.*
…

Вы можете выполнить это с помощью (и он обнаружит, нравится ли вашему терминалу -U Unicode или -A Ascii):

pstree -psS <PID LIST>

ИЛИ просто, вы знаете, используйте стрелку вверх в less следовать этому дереву / лесу через иерархию; это то, что я рекомендовал с подходом "Меньше значит больше".

Обычно я нахожу их на своем сервере с помощью

      ps aux | grep 'defunct'

ps aux | awk '{ print $8 " " $2 }' | grep -w Z

От: http://www.cyberciti.biz/tips/killing-zombie-process.html

Из комментариев улучшенный:

for p in $(ps jauxww | grep Z | grep -v PID | awk '{print $3}'); do
    for every in $(ps auxw | grep $p | grep cron | awk '{print $2}'); do
        kill -9 $every;
    done;
done;

Осторожно, хотя: этот также убивает процесс.

Хотя ответы Дламбина и Сорпигала превосходны и прекрасно выполняют свою работу, я просто хотел задокументировать свои выводы о том, как использоватьawkчтобы найти столбец STAT при переключении между форматами вывода вместо его жесткого кодирования:

      ps au | awk '{
    if (NR==1) {
        for (i=1; i<=NF; i++) {
            if ($i=="STAT")
                stat=i
        };
        print
    } else if ($stat~/^Z/)
        print
}'

Здесь будут перечислены все процессы вps«ориентированный на пользователя формат» и передать его в awk. В строке заголовка (NR = номер записи ==1) он пройдет все поля (вплоть до NF = количества полей) и сохранит номер поля, которому соответствует строка «STAT», в переменной stat, а затем продолжит печать строки. . Для всех остальных записей (строк) он проверит этот столбец на соответствие регулярному выражению, начинающемуся с заглавной буквы Z, и только затем распечатает строку.

Сокращенная версия:

      ps au|awk '{if(NR==1){for(i=1;i<=NF;i++){if($i=="STAT")stat=i};print}else if($stat~/^Z/)print}'

Я предлагаю вам эту команду:

ps aux | awk '"[Zz]" ~ $8 { printf("%s, PID = %d\n", $8, $2); }'

Чтобы вывести список процессов зомби, попробуйте эту команду:

ps j | awk '$7 ~ "Z"'

Вам может понадобиться изменить $7 в зависимости от вашей операционной системы.

Это также вернет список их идентификаторов родительского процесса (PPID).

Чтобы попытаться убить зомби (после проверки вышеуказанной команды), попробуйте:

kill -9 $(ps j | awk 'NR>1 && $7 ~ "Z" {print $2}')

Чтобы определить своих родителей, попробуйте с pstree, лайк:

$ ps j | awk 'NR>1 && $7 ~ "T" {print $2}' | xargs -L1 pstree -sg
systemd(1)───sshd(1036)───sshd(2325)───sshd(2325)───bash(2383)───zombie(2430)
systemd(1)───sshd(1036)───sshd(2325)───sshd(2325)───bash(2383)───zombie(2431)
systemd(1)───sshd(1036)───sshd(2325)───sshd(2325)───bash(2383)───zombie(2432)

почему мы не сообщаем «ps», какую информацию мы хотим получить? давайте попробуем:

      read zSTAT zPPID zPID zSTAT zCMD <<< $(ps -xao stat,ppid,pid,cmd|awk '$1=="Z" {print $1" "$2" "$3" "$4}')
[[ ! -z ${zPPID} ]] && echo "Zombie found! PID: "${zPID}" ("${zCMD}"), Parent to kill: "${zPPID}

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

проверка того, пожат ли зомби или нет, может быть быстрее, если мы проверим только один параметр:

      zombie=$(ps -xao pid|awk '$1=="'${zPID}'" {print $1}')
[[ ! -z ${zombie} ]] && sudo kill -KILL ${zPPID}
Другие вопросы по тегам