Android 中的卡顿丢帧原因概述 - 应用篇
在Android 中的卡顿丢帧原因概述 - 系统篇[1] 这篇文章中我们列举了系统自身原因导致的手机卡顿问题 , 这一篇文章我们主要列举一些由于 App 自身原因导致的卡顿问题. 各位用户在使用 App 的时候 , 如果遇见卡顿现象 , 先别第一时间骂手机厂商优化烂 , 先想想是不是这个 App 自己的问题.
Android 手机使用中的卡顿问题 , 一般来说手机厂商和 App 开发商都会非常重视 , 所以不管是手机厂商还是 App 开发者 , 都会对卡顿问题非常重视 , 内部一般也会有专门的基础组或者优化组来进行优化 . 目前市面上有一些非常棒的第三方性能监控工具 , 比如腾讯的 Matrix ; 手机厂商一般也会有自己的性能监控方案 , 由于可以修改源码和避免权限问题 , 所以手机厂商可以拿到更多的数据 , 分析起来也会更方便一些.
说回流畅度 , 其实就是操作过程中的丢帧 , 本来一秒中画面需要更新 60 帧,但是如果这期间只更新了 55 帧 , 那么在用户看来就是丢帧了 , 主观感觉就是卡了 , 尤其是帧率波动 , 用户的感知会更明显. 引起丢帧的原因非常多, 有硬件层面的 , 有软件层面的 , 也有 App 自身的问题. 所以这一部分我分为四篇文章去讲 , 会简单讲一下哪些原因会用户觉得卡顿丢帧 :
Android 中的卡顿丢帧原因概述 - 方法论[2] Android 中的卡顿丢帧原因概述 - 系统篇[3] Android 中的卡顿丢帧原因概述 - 应用篇[4] Android 中的卡顿丢帧原因概述 - 低内存篇[5]
Android App 自身导致的性能问题
在Android 中的卡顿丢帧原因概述 - 系统篇[6] 这篇文章中我们列举了系统自身原因导致的手机卡顿问题 , 这一篇文章我们主要列举一些由于 App 自身原因导致的卡顿问题. 各位用户在使用 App 的时候 , 如果遇见卡顿现象 , 先别第一时间骂手机厂商优化烂 , 先想想是不是这个 App 自己的问题.
这些实际的案例 , 很多都可以在 Systrace 上看出来 , 所以我的很多贴图都是 Systrace 上实际被发现的问题 , 如果你对 Systrace 不了解 , 可以查看这个 Systrace 系列[7] , 这里你只需要知道 , Systrace 从系统全局的角度 , 来展示当前系统的运行状况 , 通常被用来 Debug Android 性能问题 .
1.App 主线程执行时间长
主线程执行 Input \ Animation \ Measure \ Layout \ Draw \ decodeBitmap 等操作超时都会导致卡顿 , 下面就是一些真实的案例
Measure \ Layout 耗时\超时 (或者没有调度到)
Draw 耗时
Animation 回调耗时
View 初始化耗时 (PlayStore)
List Item 初始化耗时(WeChat)
decodeBitmap 耗时 (或者没有调度到)
2.uploadBitmap 耗时
这里的 uploadBitmap 主要是 upload bitmap to gpu 的操作 , 如果 bitmap 过大 , 或者每一帧内容都在变化 , 那么就需要频繁 upload , 导致渲染线程耗时.
3.BuildDrawingCache 耗时
应用本身频繁调用 buildDrawingCache 会导致主线程执行耗时从而导致卡顿 , 从下图来看, 主线程每一帧明显超过了 Vsync 周期
微信对话框有多个动态表情的时候, 也会出现这种情况导致的卡顿
4.使用 CPU 渲染而不是 GPU 渲染
如果应用在 Activity 中设置了软件渲染, 那么就不会走 hwui , 直接走 skia, 纯 cpu 进程渲染, 由于这么做会加重 UI Thread 的负载, 所以大部分情况下这种写法都会导致卡顿 , 详细技术分析可以看这篇文章 Android 中的 Hardware Layer 详解[8]
5.主线程 Binder 耗时
Activity resume 的时候, 与 AMS 通信要持有 AMS 锁, 这时候如果碰到后台比较繁忙的时候, 等锁操作就会比较耗时, 导致部分场景因为这个卡顿, 比如多任务手势操作
6.游戏 SurfaceView 内容绘制不均匀
这一项指的是游戏自身的绘制问题, 会导致总是不能满帧去跑, 如下图, 红框部分是 SurfaceFlinger 显示掉帧, 原因是底下的游戏在绘制的时候, 刚好这一帧超过了 Vsync SF 的信号.这种一般是游戏自身的问题.
7.WebView 性能不足
应用里面涉及到 WebView 的时候, 如果页面比较复杂, WebView 的性能就会比较差, 从而造成卡顿
8.帧率与刷新率不匹配
如果屏幕帧率和系统的 fps 不相符 , 那么有可能会导致画面不是那么顺畅. 比如使用 90 Hz 的屏幕搭配 60 fps 的动画
9.应用性能跟不上高帧率屏幕和系统
部分应用由于设计比较复杂, 每一帧绘制的耗时都比较长 , 这么做的话在 60 fps 的机器上可能没有问题 , 但是在 90 fps 的机器上就会很卡, 因为从 60 -> 90 , 每帧留给应用的绘制时间从 16.6 ms 变成了 11.1 ms , 如果没有在 11.1 ms 内完成, 就会出现掉帧的情况.
如下图, 这个 App 的性能比较差, 每一帧耗时都很长
10.主线程 IO 操作
主线程操作数据库 使用 SharedPerforence 的 Commit 而不是 Apply
11.WebView 与主线程交互
与 WebView 进行交互的时候, 如果 WebView 出现问题, 那么也会出现卡顿
微信文章页卡顿
12.RenderThread 耗时
RenderThread 自身比较耗时, 导致一帧的时长超过 Vsync 间隔.
渲染线程耗时过长阻塞了主线程的下一次 sync
13.多个 RenderThread 同步导致主线程卡顿
有的 App 会产生多个 RenderThread ,在某些场景下 RenderThread 在 sync 的时候花费比较多的时间,导致主线程卡顿
adb shell ps -AT | grep 10300 | grep RenderThread
u0_a170 10300 16228 6709 2693260 305172 SyS_epoll_wait 0 S RenderThread
u0_a170 10300 17394 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17395 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17396 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17397 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17399 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17400 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17401 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
u0_a170 10300 17402 6709 2693260 305172 futex_wait_queue_me 0 S RenderThread
总结
Android 原生系统是一个不断进化的过程 , 目前已经进化到了 Android Q , 每个版本都会解决非常多的性能问题 , 同时也会引进一些问题 ; 到了手机厂商这里 , 由于硬件差异和软件定制 , 会在系统中加入大量的自己的代码 , 这无疑也会影响系统的性能 . 同样由于 Android 的开放 , App 的质量和行为也影响着整机的用户体验.
本篇主要列出了 App 自身的实现问题导致的流畅性问题 , Android App 最大的问题就是质量良莠不齐 , 不同于 App Store 这样的强力管理市场 , Android App 不仅可以在 Google Play 上面进行安装 , 也可以在其他的软件市场上面安装 , 甚至可以下载安装包自行安装 , 可以说上架的门槛非常低 , 那么质量就只能由 App 开发者自己来把握了.
许多大厂的 App 质量自然不必多说 , 他们对性能和用户体验都是非常关注的 , 但也会有需求和功能过多导致的性能问题 , 比如微信就非常占内存 ; 新版本的 QQ 要比之前版本的使用起来流畅性差好多 . 中小厂的 App 就更不用说了. 再加上 Android 平台的开放性 , 需要 App 玩起来黑科技 , 什么保活 \ 相互唤醒 \ 热更新 \ 跑后台任务等 . 站在 App 开发者的角度来说这无可厚非 , 但是系统开发者则希望系统能在用户使用的时候 , 前后台 App 都能有正常的行为 , 来保证前台 App 的用户体验 . 也希望 App 开发者能重视自己 App 的性能体验 , 给用户一个好印象.
系统这边发现 App 自身的性能问题 , 且在其他厂商的手机上也是一样的表现的时候 , 通常会与 App 开发者进行联系 , 沟通一起解决 .
大家可以看看这个问题 : 当手机厂商说安卓手机性能优化的时候,他们到底在做什么[9]
参考资料
Android 中的卡顿丢帧原因概述 - 系统篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-System/
[2]Android 中的卡顿丢帧原因概述 - 方法论: https://www.androidperformance.com/2019/09/05/Android-Jank-Debug/
[3]Android 中的卡顿丢帧原因概述 - 系统篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-System/
[4]Android 中的卡顿丢帧原因概述 - 应用篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-App/
[5]Android 中的卡顿丢帧原因概述 - 低内存篇: https://www.androidperformance.com/2019/09/18/Android-Jank-Due-To-Low-Memory/
[6]Android 中的卡顿丢帧原因概述 - 系统篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-System/
[7]Systrace 系列: https://www.androidperformance.com/2019/05/26/Android_Systrace_0/
[8]Android 中的 Hardware Layer 详解: https://www.androidperformance.com/2019/07/27/Android-Hardware-Layer/
[9]当手机厂商说安卓手机性能优化的时候,他们到底在做什么: https://www.zhihu.com/question/335226118/answer/751587534