linux下僵尸进程的查找和处理方法

在 Linux 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。当用ps命令观察进程的执行状态时,看到这些进程的状态栏为defunct。僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。

如果父进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统的进程表容量是有限的,所能使用的进程号也是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。

所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。而且由于调度程序无法选中Defunct 进程,所以不能用kill命令删除Defunct 进程。下面我们来看看如何查询僵尸进程和相关的处理手段。

1.查找僵尸进程的方法

可以使用top命令进行查看,右上角的zombie就是僵尸进程数,如果看到数值不为0,可以通过下面命令查看具体的僵尸进程情况

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

defunct僵尸进程可以用过下面命令进行检查

ps -A|grep defunct

2.杀掉父进程来回收僵尸进程

可以通过以下方法进行僵尸进程的清除,一般僵尸进程不能杀掉,我们需要kill掉它的父进程(ppid)

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9

3.恢复挂起的父进程来回收僵尸进程

我们可以使用SIGCONT信号来恢复挂起的父进程,然后杀掉父进程的方式来回收僵尸进程

给父进程发送 SIGCONT (kill -18) 可以将父进程从暂停中恢复,然后继续 wait() 子进程正常结束。
可以使用如下进程查询父进程是否挂起

ps -p <ppid> -o stat

如果状态是 T,表示进程被暂停,可以使用 SIGCONT 恢复

kill -18 <ppid>

父进程恢复以后然后父进程可以继续wait() 子进程结束,但是这种方式并不是所有场景有效,可能由于程序本身原因父进程再次挂起。

4.卡在存储上的僵尸进程回收

cat /proc/<ppid>/status

如果看到D状态,这种情况下可以df或者ls挂载到存储的目录是否卡死,如果是的可以清理挂载点,如果不行先强行取消挂载,可以使用umount和fuser命令等。

5.卡在设备锁上的僵尸进程回收

我们常见的是gpu死锁

cat /proc/<ppid>/status

查看堆栈

cat /proc/<ppid>/stack

查看子进程的堆栈

ps -ef --forest | grep <ppid>

可以使用fuser查看是哪些进程使用gpu

fuser -v /dev/nvidia*

然后可以尝试杀掉这些进程或者直接重启gpu

6.容器中的僵尸进程回收

cat /proc/<ppid>/cgroup

可以根据我此前的笔记查找对应的pod,https://sulao.cn/post/985,然后可以杀掉这个重启

nerdctl -n k8s.io rm -f <pod_id>

可以尝试下杀掉所有异常容器

nerdctl -n k8s.io ps -a | grep -E 'Exited|Created|Dead|Paused' | awk '{print $1}' | xargs -r nerdctl -n k8s.io rm -f

7.重启操作系统回收僵尸进程

上述所有操作都没有效果,最终也只能重启操作系统来回收僵尸进程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.sulao.cn/post/887

评论列表

0%