cpu逐渐增高_性能分析(4)- iowait 使用率过高案例

性能分析小案例系列,可以通过下面链接查看哦

https://www.cnblogs.com/poloyy/category/1814570.html

前言

前面两个案例讲的都是上下文切换导致的 CPU 使用率升高

这一篇就来讲讲等待 I/O 导致的 CPU 使用率升高的案例

进程状态

详解进程状态

https://www.cnblogs.com/poloyy/p/13413770.html

不可中断状态

当 iowait 升高时,进程很可能因为得不到硬件的响应,而长时间处于不可中断状态

不可中断也是为了保护进程数据和硬件状态一致,并且正常情况下,不可中断状态在很短时间内就会结束

所以,短时的不可中断进程,一般可以忽略

但如果系统或硬件发生了故障,进程可能会在不可中断状态保持很久,甚至导致系统中出现大量不可中断进程。这时,就得注意下,系统是不是出现了 I/O 等性能问题

僵尸进程

多进程引用很容易碰到的问题

正常情况

一个进程创建了子进程后,它应该通过系统调用 wait() 或 waitpid() 等待子进程结束,回收子进程的资源

而子进程在结束时,会向它的父进程发送 SIGCHLD信号

所以,父进程还可以注册 SIGCHLD信号的处理函数,异步回收资源

异常情况

如果父进程没有回收资源,或是子进程执行太快,父进程还没来得及处理子进程状态,子进程就已经提前退出,那这时的子进程就会变成僵尸进程

形象比喻:父亲应该一直对儿子负责, 善始善终,如果不作为或者跟不上,都会导致“问题少年”的出现

重点

僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡,或者在父进程退出后,由 init 进程回收后也会消亡

一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态

大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建

大量不可中断状态和僵尸状态进程的案例

系统配置

Ubuntu 18.04, 2 CPU,2GB 内存

前置条件:已运行案例应用

通过 ps 命令查看案例进程

ps aux | grep /app

结果分析

多个 app 进程已启动

状态有 Ss+、D+、R+

小s:表示这个进程是一个会话的领导进程

+:表示前台进程组

什么是会话和进程组

它们是用来管理一组相互关联的进程

进程组:比如每个子进程都是父进程所在组的成员

会话:共享同一个控制终端的一个或多个进程组

会话和进程组的场景类比

通过 SSH 登录服务器,就会打开一个控制终端(TTY),这个控制终端就对应 一个会话

而在终端中运行的命令以及它们的子进程,就构成了一个个的进程组

在后台运行的命令,构成后台进程组

在前台运行的命令,构成前台进程组

通过 top 查看系统状况

结果分析

平均负载,过去 1min、5min、15min 的平均负载依次减少,说明平均负载正在升高

而 1min 内的平均负载已经达到系统 CPU 个数,说明系统很可能存在性能瓶颈

115 zombie 说明僵尸进程比较多,而且在不停增加,有子进程在退出时没被清理

用户 CPU 和系统 CPU 都不高,但 iowait分别是 60.5% 和 94.6%,好像有点儿不正常,导致系统的平均负载升高

有两个处于 D 状态的 app 进程,可能在等待 I/O

查看系统的僵尸进程

ps -e -o stat,ppid,pid,cmd | egrep '^[Zz]'或ps -ef | grep "defunct"

一堆 app 僵尸进程

iowait 分析

一提到 iowait 升高,首先会想要查询系统的 I/O 情况

运行 dstat 命令,观察 CPU 和 I/O 的使用情况

dstat 1 10

当 iowait 升高(wai)时,磁盘的读请求(read)都会很大(M)

这说明 iowait 的升高跟磁盘的读请求有关,很可能就是读磁盘导致的

找到读磁盘的进程

通过 top 找到 D 状态的两个 app 进程

不可中断状态代表进程在跟硬件进行交互,很可能就是读磁盘

两个 app 进程的 PID 分别是12407、12406

通过 pidstat 查看 app 进程的 I/O 情况

pidstat -d -p 12407 1 5

-d 展示 I/O 统计数据

-p 指定进程号

间隔 1 秒输出 5 组数据

kB_rd表示每秒读的 KB 数, kB_wr表示每秒写的 KB 数,iodelay 表示 I/O 的延迟(单位是时钟周期)

它们都是 0,那就表示此时没有任何的读写,说明问题不 是 12407 进程导致的,也并不是12406 进程导致的

通过 pidstat 查看系统的 I/O 情况

pidstat -d 1 10

能看到其实的确是 app 进程在读,只不过每过几秒都会有新的 app 进程在读【pid 在不断变化】

可以确认,是 app 进程的问题

通过 ps 命令查看一直变化的 app 进程状态

前面讲到读磁盘的 app 进程 PID 一直在变化,那么就来看看已经没在读磁盘的进程的进程状态是怎么样的

ps aux | grep 15973

这进程已经是 Z 状态,就是僵尸进程了

僵尸进程都是已经退出的进程, 所以就没法儿继续分析它的系统调用

关于僵尸进程的处理方法,我们一会儿再说,现在还是继续分析 iowait 的问题

通过 perf 录制性能事件

系统 iowait 的问题还在继续,但是 top、pidstat 这类工具已经不能给出更多的信息了

此时可以通过 perf 动态跟踪性能事件

perf record -g

15s 后 ctrl+c 终止录制

查看报告,分析报告

perf report

app 的确在通过系统调用 sys_read() 读取数据

并且从 new_sync_read 和 blkdev_direct_IO 能看出,进程正在对磁盘进行直接读,也就是绕过了系统缓存,每个读请求都会从磁盘直接读,这就可以解释观察到的 iowait 升高了

修复源码之后,通过 top 命令验证

iowait 已经非常低了,只有 0.3%

说明修改源码已经成功修复了 iowait 高的问题

不过,仔细观察僵尸进程的数量,会发现,僵尸进程还在不断的增长中

处理和分析僵尸进程

僵尸进程是因为父进程没有回收子进程的资源而出现的

解决僵尸进程需要先找出父进程,然后在父进程里解决

通过 pstree 找到某个 app 进程的父进程

pstree -aps 51780

51780 进程的父进程是 51688,也就是 app 应用

通过 ps 查看所有僵尸进程的父进程

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

所有僵尸进程的父进程都是 51688,从而确认 51688 就是僵尸进程的父进程

查看 app 应用程序的代码

查看 app 应用程序的代码,看看子进程结束的处理是否正确

有没有调用 wait() 或 waitpid()

或有没有注册 SIGCHLD信号的处理函数

把 wait() 放到了 for 死循环的外面,也就是说, wait()  函数实际上并没被调用到,把它挪到 for 循环的里面就可以了

改完源码,通过 top 验证一下

僵尸进程(Z 状态)没有了, iowait 也是 0,问题终于全部解决了

总结

这个案例是因为磁盘 I/O 导致了 iowait 升高

不过,iowait 高并不一定代表 I/O 有性能瓶颈

当系统中只有 I/O 类型的进程在运行时,iowait 也会很高,但实际上,磁盘的读写远没有达到性能瓶颈的程度

分析整体思路

通过 top查看系统资源情况

发现平均负载逐渐升高,iowait(wa)比较高,但用户态和内核态 CPU 使用率并不算高

查看是否有 CPU 使用率偏高的进程,发现有 D 状态的进程,可能是在等待 I/O 中

过一阵子会变成 Z 状态进程,且 CPU 使用率上升,然后会看到 zombie 进程数逐渐增加

可以得到两个结论:僵尸进程过多,应该是父进程没有清理已经结束的子进程的资源;iowait 的上升导系统平均负载上升

因为是 iowait 较高,可以通过 dstat 查看系统的 I/O 情况,会发现每次 iowait 升高,读磁盘请求都会很大

通过pidstat -d查看 D 状态进程的 I/O 情况,但发现并没有有效信息

通过pidstat -d直接查看系统的 I/O 情况,可以发现不断有新进程在进行读磁盘操作

通过 ps命令查看刚刚 D 状态进程当前的进程状态,发现已经变成僵尸进程

通过perf record 录制性能事件,然后通过perf report查看性能报告,可以发现 app 进程都是直接读磁盘,而不经过系统缓存

通过 pstree 找到 Z 状态进程的父进程

通过 ps 命令确认所有僵尸进程的父进程

找到父进程源代码,检查 wait() / waitpid()的是否会成功调用,或是 SIGCHLD信号处理函数的注册就行了

修改完全部源码后,重新运行应用,通过 top验证是否还有 iowait 过高和出现 zombie 进程的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 安卓APP CPU 使用率的正常值范围会受到很多因素的影响,例如应用程序的性质、设备的处理器类型、应用程序的使用方式等等。一般来说,在正常使用情况下,应用程序的 CPU 使用率应该保持在 10% 到 30% 的范围内。当应用程序需要执行一些复杂的计算任务、或者需要加载大量数据时,CPU 使用率可能会达到 50% 或更。如果应用程序的 CPU 使用率持续超过 50%,可能会导致设备变得卡顿或者出现其他性能问题。因此,开发者需要通过对应用程序的优化,尽可能降低 CPU 使用率,提应用程序的性能和用户体验。 ### 回答2: 安卓APP的CPU使用率在不同场景下会有一定的变化,但通常情况下正常值范围在10%到50%之间。 在待机或轻度使用的情况下,例如平时只打开一些基础应用、浏览网页等简单操作,CPU使用率应该在10%到20%左右。这是因为这些操作并不需要太多的计算资源,CPU使用率相对较低。 而在运行一些相对复杂的应用或进行多任务操作时,例如打开多个应用、进行游戏或者使用大型应用等,CPU使用率就会增高。在这种情况下,CPU使用率可能会在20%到50%之间波动。这是因为这些应用或任务需要较多的计算和处理资源,而CPU会相应地增加使用率来满足这些需求。 需要注意的是,在特定情况下,如进行复杂的游戏或使用较为庞大的应用时,CPU使用率可能会突破50%。但如果超过70%以上,或者持续于50%的时间较长,那可能表示存在一些问题。例如应用出现了卡顿、发热或电量消耗过快等情况,可能需要检查是否存在资源浪费或其他性能问题。 总的来说,安卓APP的CPU使用率会受到使用场景和应用需求的影响而有所波动。在正常情况下,CPU使用率在10%到50%之间是比较正常的范围。如果CPU使用率持续较或出现异常情况,可能需要考虑优化应用或系统设置,以提升设备的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值