Files
mkdocs/docs/学习笔记/基础性能问题分析(ODM).md
2026-01-30 18:06:48 +08:00

13 KiB
Raw Permalink Blame History

基础性能问题分析ODM

一、卡顿类问题

1. 滑动类卡顿

一般为长列表滑动等单一页面操作页面应用主线程持续出帧从SurfaceFlinger也可以看到有一个Activity持续输出buffer有快滑手指离屏后页面仍在滑动对应在input消息后有一段时间出帧慢滑手指不离屏滑动会有持续的input消息两种情况。这类场景需关注正常绘制流程应用主线程-RenderThread线程-SF即可PS有些应用为了兼容性采用webview以及flutter绘制这个需要单独分析

2. 动画类卡顿

用户操作后执行固定的动画效果多数情况在systrace中会有animatortag打印。

2.1 页面跳转动画

两个Activity之间切换的动画一般为系统system_server动画对应在system_server的android.anim.if线程出帧没有渲染线程直接通过调用SF的setTransactionState方法参与画面合成。

2.2 转屏动画

应用需要转屏操作时一般会先冻结屏幕等转屏后的页面准备好后解冻执行转屏动画冻屏时间过长会给人反应慢的感觉也会有人认为这是卡顿因此冻屏时间也需关注。转屏动画与页面跳转动画一样在android.anim.if线程出帧。

2.4 桌面动画

桌面与应用之间的页面跳转包括在桌面、recently页面点击应用冷、热启动过程以及从应用回到桌面、recently页面等操作都可能会执行桌面动画。具体场景可根据input消息打印、activityResume、activityStop等方法的位置判断。桌面动画会在应用主线程正常出帧launcher主线程-RT线程-SF

3. 问题分析步骤

3.1 明确问题场景

根据问题描述、截屏、视频、log、systrace等信息初步判断问题场景以便决定后续分析方向。

3.1.1 整机卡顿、卡死、卡主不动

这类问题常见于项目版本初期,或者市场反馈问题。

整机卡顿问题多是多个场景在同一时间段发生卡顿的问题,也有部分问题可能来自实际用户,实际卡顿场景可能很单一但用户描述不清晰,这时就需要根据已有信息判断是否发生卡顿并拆解出卡顿场景进一步分析。

遇到整机卡顿、卡住、卡死问题首先排除是否发生ANR、crash等问题然后拆解出具体卡顿场景继续分析如果拆解出多个不同场景卡顿需逐一分析根据systemserver中的focusap以及iq事件等可以大体确认场景方法对应各场景分析思路。一般容易造成系统短时间多个场景卡顿的情况如input上报异常、SF出帧HWC合成耗时、CPU限频关核、低内存、高负载等。

3.1.2 单一场景卡顿

根据问题描述或视频、截屏初步判断是卡顿问题还是功能性问题,卡顿场景是否是性能责任田等,保证问题快速流转。如果测试提供信息不全且本地无获取条件及时与测试沟通请测试提供。性能自身问题需明确:

  • 问题自检卡顿场景、问题信息systrace、log、截屏、录屏等是否充足有效、本地能否复现、对比机能否复现等
  • 问题等级:路径复杂度(及复现概率)、卡顿程度、对比机现象是否一致等。

处理问题时优先关注等级较高的问题,如果测试机卡顿程度比同场景对比机严重,很大可能是系统问题,也需关注。

3.2 定位问题位置

确认问题场景后可找到对应出帧线程核对卡顿时间从问题描述、截屏、录屏、log等信息中提取、input消息、出Buffer情况SF、页面生命周期有跳转情况等条件大体圈定systrace范围如果没有抓到及时请测试复测。

3.3 确认卡顿点并分析原因

常见的卡顿问题大都是丢帧引起的,但造成丢帧的原因多种多样无法全部列举,这里仅列举如何判断是否发生丢帧

3.3.1 丢帧

对于一个帧率60的设备如果1秒内屏幕显示画面小于60即发生丢帧。对于我们来说仅关注应用输出Buffer到SF以及SF输出给屏幕过程是否丢帧即可。

3.3.1.1 应用丢帧

由于3Buffer机制应用主线程、RT线程出帧稍慢并不一定会丢帧比较准确的判断应用丢帧的方法是看SF进程下应用输出Buffer的泳道是否连贯、是否每个VSync周期都有可用Buffer供SF消费。

二、启动响应

响应速度概述

响应速度是应用App性能的重要指标之一。响应慢通常表现为点击效果延迟、操作等待或白屏时间长等主要场景包括

  • 应用启动场景,包括冷启动、热启动、温启动等
  • 界面跳转场景包括应用内页面跳转、App之间跳转
  • 其他非跳转的点击场景(开关、弹窗、长按、控件选择、单击、双击等)
  • 亮灭屏、开关机、解锁、人脸识别、拍照、视频加载等场景

从原理上来说响应速度场景往往是由一个input事件以Message的形式给到需要处理的应用主线程触发比如点击、长按、电源键、指纹等由一个或者多个Message的执行结束为结尾而这些Message中一般都有关键的界面绘制相关的Message。衡量一个场景的响应速度我们通常从事件触发开始计时到应用处理完成计时结束这一段时间就称为响应时间。

由于响应速度是一个比较主观的性能指标而流畅度就是一个很精确的指标掉一帧就是掉一帧而且根据角色的不同对这个性能指标的判定也不同比如Android系统开发者和应用开发者以及测试同学对应用冷启动的起点和终点就有不同的判定

  1. 系统开发者往往从input中断开始看部分以应用第一帧为结束点因为比较好计算部分以应用加载完成为结束点比较主观除非结束点比较容易通过工具去判断主要是以优化应用的整体性能为主涉及到的方面就比较广包括input事件传递、SystemServer、SurfaceFlinger、Kernel、Launcher等
  2. App开发者一般从Application的onCreate或者attachContext开始看大部分以界面完全加载或者用户可操作为结束点因为是自己的应用结束点在代码里面可以主动加主要还是以优化应用自身的启动速度为主市面上讲启动速度优化的大部分是讲这部分
  3. 测试同学则更多从用户的真实体验角度来看,以桌面点击应用图标且应用图标变色为第一帧,内容完全加载为结束点。测试过程一般使用高速相机•自动化,通过机械手和图形识别技术,可以自动进行响应速度测试并抓取相关的测试数据

响应速度问题分析思路分清起点和终点

分析响应速度,最重要的是要找到起点和终点,上一节讲到,不同角色的开发者,对这个性能指标的判定起点和终点都不一样;而且这个指标有很主观的成分,所以在开始的时候,就要跟各方来确定好起点和终点,具体的数值标准,下面一些手段可以帮助大家来确定

  1. 竞品分析。一般来说响应速度这个指标都会有一个对标的竞品竞品手机或者竞品App相同的条件下竞品手机或者竞品App从点击到响应花费了多少时间可以作为一个标准
  2. 对比前一个版本。有时候系统进行大版本升级或者App进行版本迭代那么上一个版本的数据就可以拿来作为标准进行对比

一般来说起点都比较好确定无非是一个点击事件或者一个自定义的触发事件而终点的确定就比较麻烦比如如何确定一个复杂的App比如淘宝启动完成的时间点用Systrace的第一帧或者Log输出的Displayed时间或者onWindowFocusChange回调的时间显然是不准确的。目前市面上使用高速相机+图像识别来做是一个比较主流的做法

响应速度常见问题

Android 系统自身原因导致响应慢

下面这些列举的是Android系统自身的原因与Android机器的性能有比较大的关系性能越差越容易出现响应速度问题。下面就列出了Android系统原因导致的App响应速度出现问题的原因以及这个时候App端在Systrace中的表现

  1. CPU频率不足

    • App端的表现主线程处于Running状态但是执行耗时变长
  2. CPU大小核调度关键任务跑到了小核

    • App端的表现Systrace看主线程处于Running状态但是执行耗时变长
  3. SystemServer 繁忙,主要影响

    • 响应App主线程Binder调用处理耗时
      • App端的表现Systrace看主线程处于Sleep状态在等待Binder调用返回
    • 应用启动过程逻辑处理耗时
      • App端的表现Systrace看主线程处于Sleep状态在等待Binder调用返回
  4. SurfaceFlinger 繁忙主要影响应用的渲染线程的dequeueBuffer、queueBuffer

    • App端的表现Systrace看应用渲染线程的dequeueBuffer、queueBuffer处于Binder等待状态
  5. 系统低内存低内存的时候很大概率出现下面几种情况都会对SystemServer和应用有影响

    • 低内存的时候有些应用会频繁被杀和启动而应用启动时一个重操作会占用CPU资源导致前台App启动变慢
      • App端的表现Systrace看应用主线程Runnable状态变多Running状态变少整体函数执行耗时增加
    • 低内存的时候很容易触发各个进程的GC用于内存回收的HeapTaskDeamon、kswapd0出现非常频繁
      • App端的表现Systrace看应用主线程Runnable状态变多Running状态变少整体函数执行耗时增加
    • 低内存会导致磁盘IO变多如果频繁进行磁盘IO由于磁盘IO很慢那么主线程会有很多进程处于等IO的状态也就是我们经常看到的UninterruptibleSleep
      • App端的表现Systrace看应用主线程UninterruptibleSleep和UninterruptibleSleep-IO状态变多Running状态变少整体函数执行耗时增加
  6. 系统触发温控频率被限制由于温度过高CPU最高频率被限制

    • App端的表现主线程处于Running状态但是执行耗时变长
  7. 整机CPU繁忙可能有多个高负载进程同时在运行或者有单个进程负载过高跑满了CPU

    • App端的表现从Systrace来看CPU区域的任务非常满所有的核心上都有任务在执行App的主线程和渲染线程多处于Runnable状态或者频繁在Runnable和Running之间切换

代码逻辑

  1. 是否在等Binder耗时比较久Sleep状态→检测Binder服务端一般是SystemServer

  2. 是否在等待子线程返回数据Sleep状态→应用自身问题通过查看wakeup信息来找到依赖的子线程

  3. 是否在等待子进程返回数据Sleep状态→应用自身问题通过查看wakeup信息来找到依赖的子进程或者其他进程(一般是ContentProvider所在的进程)

  4. 是否有大量的Runnable→系统问题查看CPU部分看看是否已经跑满

  5. 是否有大量的IO等待UninterruptibleSleep|WakeKill-BlockI/O→检查系统是否已经低内存

  6. RenderThread是否执行dequeueBuffer和queueBuffer耗时→查看SurfaceFlinger

  7. 如果分析是系统的问题则根据上面耗时的点查看系统对应的部分一般情况要优先查看系统是否异常参考上面列出的的系统原因主要看下面四个区域Systrace

  8. Kernel 区域

    • 查看关键任务是否跑在了小核→一般小核是0-3也有特例如果启动时候的关键任务跑到了小核执行速度也会变慢
    • 查看频率是否没有跑满→表现是核心频率没有达到最大值比如最大值是2.8Ghz但是只跑到了1.8Ghz,那么可能是有问题的
    • 查看CPU使用率是否已经跑满了→表现是CPU区域八个核心上任务和任务之间没有空隙
    • 查看是否低内存
      • 应用进程状态有大量的UninterruptibleSleep|WakeKill-BlockI/O
      • HeapTaskDeamon任务执行频繁
      • kswapd0任务执行频繁
  9. SystemServer 进程区域

    • input 事件读取和分发是否有异常→表现是input事件传递耗时比较少见
    • binder 执行是否耗时→表现是SystemServer对应的Binder执行代码逻辑耗时
    • binder 等am、wm锁是否耗时→表现是SystemServer对应的Binder都在等待锁可以通过wakeup信息跟踪等锁情况分析等锁是不是由于应用导致的
    • 是否有应用频繁启动或者被杀→在Systrace中查看startProcess或者查看EventLog