android优化卡顿
‘壹’ Android 中的卡顿丢帧原因概述 - 应用篇
在探讨Android设备的卡顿与丢帧问题时,我们首先需要区分问题的根源是系统层面还是应用层面。这篇文章专注于介绍由App自身引发的卡顿问题,帮助用户在遇到设备卡顿现象时,能够首先从应用角度进行排查。
卡顿与丢帧问题在Android设备上非常常见,这涉及到操作过程中帧率的波动。通常,设备每秒需要更新60帧以保证流畅体验,若实际更新帧数少于60,用户就会感知到卡顿。引起丢帧的原因多样,包括硬件、软件层面问题以及App自身的设计缺陷。
对于应用开发者而言,理解并解决这些问题对于提升用户体验至关重要。以下列举了导致卡顿与丢帧的一些常见原因:
1. 主线程执行时间过长:主线程执行如输入处理、动画、测量布局、绘图、位图解码等操作时,若耗时超过预期,会直接影响设备性能,导致卡顿。
2. Measure和Layout耗时过长:这些操作在视图构建过程中占据重要地位,耗时或调度不及时,会直接导致卡顿。
3. 动画回调耗时:动画处理中的回调若处理时间过长,同样会影响性能,导致卡顿现象。
4. 视图初始化耗时:如在应用中初始化列表项,若耗时过长,会引发卡顿。
5. decodeBitmap耗时:位图解码操作过长,可能导致渲染线程性能下降,进而影响整体性能。
6. uploadBitmap耗时:频繁上传位图至GPU,特别是对于大图或动态变化的图,会加重渲染线程负担,导致卡顿。
7. BuildDrawingCache耗时:应用频繁调用此操作,可能导致主线程执行时间过长,影响性能。
8. CPU渲染而非GPU渲染:不当的渲染策略可能导致UI线程负载加重,引起卡顿。
9.主线程Binder操作耗时:在Activity resume时,与AMS通信可能需要等待锁操作,这在后台繁忙时会增加耗时,引起卡顿。
10.游戏SurfaceView内容绘制不均匀:游戏自身的绘制问题可能导致帧率波动,引起卡顿。
11. WebView性能不足:复杂页面的渲染可能导致WebView性能下降,影响整体流畅度。
12.帧率与刷新率不匹配:屏幕帧率与系统帧率不匹配,可能导致画面显示不流畅。
13.应用性能跟不上高帧率屏幕和系统:在高帧率设备上,应用性能不足可能导致卡顿。
总结而言,Android系统的性能优化是一个持续发展的过程,不同版本解决的问题与引入的新问题并存。手机厂商在系统中加入大量自定义代码,这在一定程度上影响了系统的整体性能。同时,Android的开放性意味着应用质量参差不齐,这直接影响用户体验。开发者需要重视应用的性能优化,以提供更好的用户体验。当发现应用存在性能问题时,系统开发者与开发者之间会进行沟通,共同寻找解决方案。理解并解决这些问题,对于提升Android应用的性能和用户体验至关重要。
‘贰’ Android流畅度评估及卡顿优化
Google定义:界面呈现是指从应用生成帧并将其显示在屏幕上的动作。要确保用户能够流畅地与应用互动,应用呈现每帧的时间不应超过16ms,以达到每秒60帧的呈现速度(为什么是60fps?)。
如果应用存在界面呈现缓慢的问题,系统会不得不跳过一些帧,这会导致用户感觉应用不流畅,我们将这种情况称为卡顿。
来源于: Google Android的为什么是60fps?
16ms意味着1000/60hz,相当于60fps。这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。12fps大概类似手动快速翻动书籍的帧率, 这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。 24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。 但是低于30fps是 无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,超过60fps就没有必要了。如果我们的应用没有在16ms内完成屏幕刷新的全部逻辑操作,就会发生卡顿。
首先要了解Android显示1帧图像,所经历的完整过程。
如图所示,屏幕显示1帧图像需要经历5个步骤:
常见的丢帧情况: 渲染期间可能出现的情况,渲染大于16ms和小于16ms的情况:
上图中应该绘制 4 帧数据 , 但是实际上只绘制了 3 帧 , 实际帧率少了一帧
判断APP是否出现卡顿,我们从通用应用和游戏两个纬度的代表公司标准来看,即Google的Android vitals性能指标和地球第一游戏大厂腾讯的PrefDog性能指标。
以Google Vitals的卡顿描述为准,即呈现速度缓慢和帧冻结两个维度判断:
PerfDog Jank计算方法:
帧率FPS高并不能反映流畅或不卡顿。比如:FPS为50帧,前200ms渲染一帧,后800ms渲染49帧,虽然帧率50,但依然觉得非常卡顿。同时帧率FPS低,并不代表卡顿,比如无卡顿时均匀FPS为15帧。所以平均帧率FPS与卡顿无任何直接关系)
当了解卡顿的标准以及渲染原理之后,可以得出结论,只有丢帧情况才能准确判断是否卡顿。
mpsys 是一种在设备上运行并转储需要关注的系统服务状态信息的 Android 工具。通过向 mpsys 传递 gfxinfo 命令,可以提供 logcat 格式的输出,其中包含与录制阶段发生的动画帧相关的性能信息。
借助 Android 6.0(API 级别 23),该命令可将在整个进程生命周期中收集的帧数据的聚合分析输出到 logcat。例如:
这些总体统计信息可以得到期间的FPS、Jank比例、各类渲染异常数量统计。
命令 adb shell mpsys gfxinfo <PACKAGE_NAME> framestats 可提供最近120个帧中,渲染各阶段带有纳秒时间戳的帧时间信息。
关键参数说明:
通过gfxinfo输出的帧信息,通过定时reset和打印帧信息,可以得到FPS(帧数/打印间隔时间)、丢帧比例((janky_frames / total_frames_rendered)*100 %)、是否有帧冻结(帧耗时>700ms)。
根据第2部分的通用应用卡顿标准,可以通过丢帧比例和帧冻结数量,准确判断当前场景是否卡顿。并且通过定时截图,还可以根据截图定位卡顿的具体场景。
如上图所示,利用gfxinfo开发的检查卡顿的小工具,图中参数和卡顿说明如下:
根据上面对gfxinfo的帧信息解析,可以准确计算出每一帧的耗时。从而可以开发出满足腾讯PerfDog中关于普通卡顿和严重卡顿的判断。
依赖定时截图,即可准确定位卡顿场景。如下图所示(此处以PerfDog截图示例):
通过第3部分的卡顿评估方法,我们可以定位到卡顿场景,但是如何定位到具体卡顿原因呢。
首先了解卡顿问题定位工具,然后再了解常见的卡顿原因,即可通过复现卡顿场景的同时,用工具去定位具体卡顿问题。
重点就是,充分利用gfxinfo输出的帧信息,对卡顿问题进行分类。
了解了高效定位卡顿的方法和卡顿问题定位工具,再熟悉一下常见的卡顿原因,可以更熟练的定位和优化卡顿。
SurfaceFlinger 负责 Surface 的合成,一旦 SurfaceFlinger 主线程调用超时,就会产生掉帧。
SurfaceFlinger 主线程耗时会也会导致 hwc service 和 crtc 不能及时完成,也会阻塞应用的 binder 调用,如 dequeueBuffer、queueBuffer 等。
后台进程活动太多,会导致系统非常繁忙,cpu io memory 等资源都会被占用,这时候很容易出现卡顿问题,这也是系统这边经常会碰到的问题。
mpsys cpuinfo 可以查看一段时间内 cpu 的使用情况:
当线程为 Runnable 状态的时候,调度器如果迟迟不能对齐进行调度,那么就会产生长时间的 Runnable 线程状态,导致错过 Vsync 而产生流畅性问题。
system_server 的 AMS 锁和 WMS 锁 , 在系统异常的情况下 , 会变得非常严重 , 如下图所示 , 许多系统的关键任务都被阻塞 , 等待锁的释放 , 这时候如果有 App 发来的 Binder 请求带锁 , 那么也会进入等待状态 , 这时候 App 就会产生性能问题 ; 如果此时做 Window 动画 , 那么 system_server 的这些锁也会导致窗口动画卡顿。
Android P 修改了 Layer 的计算方法 , 把这部分放到了 SurfaceFlinger 主线程去执行, 如果后台 Layer 过多,就会导致 SurfaceFlinger 在执行 rebuildLayerStacks 的时候耗时 , 导致 SurfaceFlinger 主线程执行时间过长。
主线程执行 Input Animation Measure Layout Draw decodeBitmap 等操作超时都会导致卡顿 。
Activity resume 的时候, 与 AMS 通信要持有 AMS 锁, 这时候如果碰到后台比较繁忙的时候, 等锁操作就会比较耗时, 导致部分场景因为这个卡顿, 比如多任务手势操作。
应用里面涉及到 WebView 的时候, 如果页面比较复杂, WebView 的性能就会比较差, 从而造成卡顿。
如果屏幕帧率和系统的 fps 不相符 , 那么有可能会导致画面不是那么顺畅. 比如使用 90 Hz 的屏幕搭配 60 fps 的动画。
由上面的分析可知对象分配、垃圾回收(GC)、线程调度以及Binder调用 是Android系统中常见的卡顿原因,因此卡顿优化主要以下几种方法,更多的要结合具体的应用来进行:
在计算机和通信领域,帧是一个包括“帧同步串行”的数字数据传输单元或数字数据包。
在视频领域,电影、电视、数字视频等可视为随时间连续变换的许多张画面,其中帧是指每一张画面。