如何查找僵尸进程?

如何查找僵尸进程?
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:~$ 

如何找到那个僵尸进程?

答案1

要杀死僵尸(进程),您必须杀死它的父进程(就像真正的僵尸一样!),但问题是如何找到它。

找到僵尸(问题回答了这部分):

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 上的更多资源:

答案2

尽管这个问题很老了,但我认为每个人都应该得到一个更可靠的答案:

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 列表。

现在您可以使用简单的 shell 循环来操作此列表

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

ps是一个强大的工具,您不需要做任何复杂的事就可以从中获取流程信息。

(此处不同过程状态的含义 -https://unix.stackexchange.com/a/18477/121634

答案3

少即是多:

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前面加上一个;如果您想要匹配时加一个星号,则可以加上一个。遗憾的是,如果您使用不突出显示行,星号将不会显示,但会为其留出空间。pJGJ

你最终会得到如下结果:


  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即可通过层次结构跟踪该树/森林;这就是我所推荐的“少即是多”方法。

答案4

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;

但要小心:这也会终止进程。

相关内容