Linux性能优化-系统存在大量不可中断的进程和僵尸进程怎么办

不可中断进程和僵尸进程

  • 不可中断进程,一般是指在进程在和硬件交互为了保护进程数据和硬件一致,系统不允许其他进程中断打断该进程。
  • 僵尸进程表示进程已经退出,但是它的父进程没有回收该进程所占用的资源。

进程运行状态

  • R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
  • D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
  • Z 是 Zombie 的缩写,如果你玩过“植物大战僵尸”这款游戏,应该知道它的意思。它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
  • S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
  • I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。

当然了,上面的示例并没有包括进程的所有状态。除了以上 5 个状态,进程还包括下面这 2 个状态。

第一个是 T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped);再向它发送 SIGCONT 信号,进程又会恢复运行(如果进程是终端里直接启动的,则需要你用 fg 命令,恢复到前台运行)。

而当你用调试器(如 gdb)调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状态,这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行。

另一个是 X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。

现象:

1.iowait太高,导致负载升高,并且达到了系统CPU的个数
2.僵尸进程不断增多

分析:

一、先分析iowait升高的原因,可能的原因是i/o问题

1.使用dstat命令查询CPU和I/O的使用情况(查看read,write请求的情况)

# 间隔1秒输出10组数据
$ dstat 1 10

2.使用top或ps查看D状态的进程

$ top

3.使用pidstat加-d参数输出I/O使用的情况

# -d展示I/O统计数据,-p指定进程号,间隔1秒输出3组数据
$ pidstat -d -p [进程号] 1 3 

4.如果通过上面的方法查看进程发现没有磁盘读写的信息,那就直接查看所有进程的I/O使用情况

# 间隔1秒输出多组数据
$ pidstat -d 1 20

5.进程直接访问磁盘就必须使用系统调用,现在来找出进程的系统调用

$ strace -p [进程号]
或者使用:
$ perf record -g
$ perf report

二、僵尸进程

1.找出僵尸进程的父进程

# -a表示命令行选项,p表示PID,s表示制定进程的父进程
$ pstree -aps [僵尸进程PID] #这里僵尸进程是3084
systemd,1 
└─dockerd,15006 -H fd:// 
		└─docker-containe,15024 --config /var/run/docker/containerd/containerd.toml 
			└─docker-containe,3991 -namespace moby -workdir... 
				└─app,4009 
					└─(app,3084)

# -A 参数列出所有进程,
# -o 自定义输出字段 我们设定显示字段为 stat(状态), ppid(进程父id), pid(进程id),cmd(命令)这四个参数
# grep -e 过滤查找做为查找Zz文件内容的样式
$ ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

3084 号进程的父进程是 4009
接着查看应用程序的代码,看看子进程结束的处理是否正确,比如有没有调用 wait() 或 waitpid() ,抑或是,有没有注册 SIGCHLD 信号的处理函数。

2.杀死僵尸进程的父进程
由于僵尸进程已经死掉了(只保留了 task_struct 结构体),而死掉的进程是无法直接 kill 的,所以一般通过杀掉父进程来间接干掉僵尸进程。
把父进程杀掉,僵尸进程会变成孤儿进程,然后过继给 1 号进程,而 1 号进程会扫描名下子进程,把 Z 状态进程回收;

$ kill -9 [僵尸进程父进程PID]
posted @   Pyke的大鲨鱼  阅读(379)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示