持续创造,加快成长!这是我参与「日新计划 10 月更文应战」的第5天,点击查看活动概况
前语
汇总了一下许多大佬的功能优化文章,知识点,首要包含:
UI优化/发动优化/溃散优化/卡顿优化/安全性优化/弱网优化/APP深度优化等等等~
本篇是第三篇:溃散优化+卡顿优化[非商业用途,如有侵权,请告知我,我会删除]
着重一下: 功能优化的开发文档跟之前的面试文档相同,需求的跟作者直接要。
三、溃散优化
3.1 溃散剖析
溃散率是衡量一个运用质量凹凸的根本目标:
- Android 溃散分为 Java 溃散和 Native 溃散:
- Java 溃散便是在 Java 代码中,呈现了未捕获反常,导致程序反常退出;
- Native 溃散又是怎样发生的呢?一般都是由于在 Native 代码中拜访不合法地址, 也或许是地址对齐呈现了问题,或许发生了程序主动 abort,这些都会发生相应的 signal 信号,导致程序反常退出。
- Native溃散的捕获流程
完好的 Native 溃散从捕获到解析的流程:
- 编译端。编译 C/C++ 代码时,需求将带符号信息的文件保存下来
- 客户端。捕获到溃散时分,将搜集到尽或许多的有用信息写入日志文件,然后选择适宜的机遇上传到服务器。
- 服务端。读取客户端上报的日志文件,寻找适宜的符号文件,生成可读的 C/C++ 调用栈。
Native 溃散捕获的难点
上面的三个流程中,最中心的是怎样样确保客户端在各种极点状况下依然能够生成溃散日志。由于在溃散时,程序会处于一个不安全的状况,假如处理不当,非常简略发生二次溃散。那么,生成溃散日志时会有哪些比较扎手的状况呢?
状况一: 文件句柄走漏,导致创立日志文件失利,怎样办?应对办法:咱们需求提早申请文件句柄 fd 预留,防止呈现这种状况。
状况二: 由于栈溢出了,导致日志生成失利,怎样办?应对办法:为了防止栈溢出导致进程没有空间创立调用栈履行处理函数,咱们一般会运用常见的 signalstack。在一些特别状况,咱们或许还需求直接替换当时栈,所以这儿也需求在堆中预留部分空间。
状况三: 整个堆的内存都耗尽了,导致日志生成失利,怎样办?应对办法:这个时分咱们无法安全地分配内存,也不敢运用 stl 或许 libc 的函数,由于它们内部完结会分配堆内存。这个时分假如持续分配内存,会导致呈现堆损坏或许二次溃散的状况。Breakpad 做的比较完全,重新封装了Linux Syscall Support,来防止直接调用 libc。
状况四: 堆损坏或二次溃散导致日志生成失利,怎样办?应对办法:Breakpad 会从原进程 fork 出子进程去搜集溃散现场,此外触及与 Java 相关的,一般也会用子进程去操作。这样即便呈现二次溃散,只是这部分的信息丢掉,咱们的父进程后边还能够持续获取其他的信息。在一些特别的状况,咱们还或许需求从子进程 fork 出孙进程。
选择适宜的溃散服务
关于许多中小型公司来说,并不主张自己去完结一套如此杂乱的体系,能够选择一些第三方的服务。现在各种渠道也是百花齐放,包含腾讯的Bugly、阿里的啄木鸟渠道、网易云捕、Google 的 Firebase 等等
3.2 溃散现场应收集哪些信息
1. 溃散信息:
- 进程名、线程名:
溃散的进程是前台进程仍是后台进程,溃散是不是发生在 UI 线程。
- 溃散仓库和类型:
归于 Java 溃散、Native 溃散,仍是 ANR
2. 体系信息
- Logcat: 这儿包含运用、体系的运转日志
- 机型、体系、厂商、CPU、ABI、Linux 版别等
- 设备状况:是否root、是否是模拟器
3. 内存信息
OOM、ANR、虚拟内存耗尽等,许多溃散都跟内存有直接联系
- 体系剩余内存:
当体系可用内存很小(低于 MemTotal 的 10%)时,OOM、许多 GC、体系频繁自杀拉起等问题都非常简略呈现
- 运用运用内存:
包含 Java 内存、RSS(Resident Set Size)、PSS(Proportional Set Size),咱们能够得出运用本身内存的占用巨细和散布
- 虚拟内存:
能够经过 /proc/self/status 得到,经过 /proc/self/maps 文件能够得到详细的散布状况,有时分咱们一般不太注重虚拟内存,可是许多相似 OOM、tgkill 等问题都是虚拟内存不足导致的
4. 资源信息
有的时分咱们会发现运用堆内存和设备内存都非常充足,仍是会呈现内存分配失利的状况,这跟资源走漏或许有比较大的联系
- 文件句柄 fd:
文件句柄的限制能够经过 /proc/self/limits 取得,一般单个进程允许翻开的最大文件句柄个数为 1024。 可是假如文件句柄超越 800 个就比较危险,需求将一切的 fd 以及对应的文件名输出到日志中,进一步排查是否呈现了有文件或许线程的走漏
- 线程数:
当时线程数巨细能够经过上面的 status 文件得到,一个线程或许就占 2MB 的虚拟内存,过多的线程会对虚拟内存和文件句柄带来压力。 根据我的经验来说,假如线程数超越 400 个就比较危险。需求将一切的线程 id 以及对应的线程名输出到日志中,进一步排查是否呈现了线程相关的问题。
- JNI:
运用 JNI 时,假如不留意很简略呈现引证失效、引证爆表等一些溃散。咱们能够经过 DumpReferenceTables 核算 JNI 的引证表,进一步剖析是否呈现了 JNI 走漏等问题。
5. 运用信息
除了体系,其实咱们的运用更懂自己,能够留下许多相关的信息
- 溃散场景
溃散发生在哪个 Activity 或 Fragment,发生在哪个事务中
- 要害操作途径
不同于开发进程详细的打点日志,咱们能够记载要害的用户操作途径,这对咱们复现溃散会有比较大的协助
- 其他自定义信息
不同的运用关心的要点或许不太相同,比方网易云音乐会重视当时播映的音乐,QQ 浏览器会重视当时翻开的网址或视频。此外例如运转时刻、是否加载了补丁、是否是全新安装或升级等信息也非常重要。
6. 其他信息
除了上面这些通用的信息外,针对特定的一些溃散,咱们或许还需求获取相似磁盘空间、电量、网络运用等特定信息。所以说一个好的溃散捕获东西,会根据场景为咱们收集满足多的信息,让咱们有更多的头绪去剖析和定位问题。当然数据的收集需求留意用户隐私,做到满足强度的加密和脱敏。
3.3 溃散剖析 三部曲
第一步:确定要点
承认和剖析要点,要害在于在日志中找到重要的信息,对问题有一个大致判断。一般来说,我主张在确定要点这一步能够重视以下几点。
1. 承认严峻程度
处理溃散也要看性价比,咱们优先处理 Top 溃散或许对事务有重大影响,例如发动、支付进程的溃散。
2. 溃散根本信息
确定溃散的类型以及反常描述,对溃散有大致的判断。
- Java 溃散类型比较显着
- Native 溃散: 需求调查 signal、code、fault addr 等内容,以及溃散时 Java 的仓库;
- ANR: 先看看主线程的仓库,是否是由于锁等候导致。接着看看 ANR 日志中 iowait、CPU、GC、system server 等信息,进一步确定是 I/O 问题,或是 CPU 竞赛问题,仍是由于许多 GC 导致卡死。
3. Logcat
Logcat 一般会存在一些有价值的头绪,日志级别是 Warning、Error 的需求特别留意。从 Logcat 中咱们能够看到当时体系的一些行为跟手机的状况,例如呈现 ANR 时,会有“am_anr”;App 被杀时,会有“am_kill”。
4. 各个资源状况
结合溃散的根本信息,咱们接着看看是不是跟 “内存信息” 有关,是不是跟“资源信息”有关。比方是物理内存不足、虚拟内存不足,仍是文件句柄 fd 走漏了。
第二步:查找共性
假如运用了上面的办法仍是不能有用定位问题,咱们能够测验查找这类溃散有没有什么共性。找到了共性,也就能够进一步找到差异,离处理问题也就更进一步 机型、体系、ROM、厂商、ABI,这些收集到的体系信息都能够作为维度聚合,找到了共性,能够对你下一步复现问题有更清晰的指引。
第三步:测验复现
“只要能本地复现,我就能解”,信任这是许多开发跟测试说过的话。有这样的底气首要是由于在安稳的复现途径上面,咱们能够采用添加日志或运用 Debugger、GDB 等各种各样的手段或东西做进一步剖析。
3.4 疑难问题:体系溃散 的处理思路
1. 查找或许的原因。
经过上面的共性归类,咱们先看看是某个体系版别的问题,仍是某个厂商特定 ROM 的问题。虽然溃散日志或许没有咱们自己的代码,但经过操作途径和日志,咱们能够找到一些置疑的点。
2. 测验规避。
查看可疑的代码调用,是否运用了不恰当的 API,是否能够替换其他的完结办法规避。
3. Hook 处理。
这儿分为 Java Hook 和 Native Hook。
溃散攻防是一个长时间的进程,咱们期望尽或许地提早防备溃散的发生,将它消灭在萌发阶段。这或许触及咱们运用的整个流程,包含人员的训练、编译查看、静态扫描作业,还有标准的测试、灰度、发布流程等。
3.5 取得logcat和Jave仓库的办法:
一. 获取logcat
logcat日志流程是这样的,运用层 –> liblog.so –> logd,底层运用ring buffer来存储数据,获取的办法有以下三种:
1. 经过logcat指令获取
- 长处:非常简略,兼容性好。
- 缺陷:整个链路比较长,可控性差,失利率高,特别是堆损坏或许堆内存不足时,根本会失利。
2. hook liblog.so完结
经过hook liblog.so 中__android_log_buf_write 办法,将内容重定向到自己的buffer中。
- 长处:简略,兼容性相对还好。
- 缺陷:要一向翻开。
3. 自定义获取代码
- 经过移植底层获取logcat的完结,经过socket直接跟logd交互。
- 长处:比较灵敏,预先分配好资源,成功率也比较高。 缺陷:完结非常杂乱
二. 获取Java 仓库
native溃散时,经过unwind只能拿到Native仓库。咱们期望能够拿到当时各个线程的Java仓库
1. Thread.getAllStackTraces()。
- 长处:简略,兼容性好。
- 缺陷: a. 成功率不高,依托体系接口在极点状况也会失利。 b. 7.0之后这个接口是没有主线程仓库。 c. 运用Java层的接口需求暂停线程
2. hook libart.so
经过hook ThreadList和Thread的函数,取得跟ANR相同的仓库。为了安稳性,咱们会在fork子进程履行。
- 长处:信息很全,根本跟ANR的日志相同,有native线程状况,锁信息等等。
- 缺陷:黑科技的兼容性问题,失利时能够用Thread.getAllStackTraces()兜底
获取Java仓库的办法还能够用在卡登时,由于运用fork进程,所以能够做到完全不卡主进程。这块咱们在后边会详细的去讲。
四、卡顿优化
4.1 什么是卡顿
卡顿,望文生义便是用户体感界面不流通。咱们知道手机的屏幕画面是依照必定频率来刷新的,理论上讲,24 帧的画面更新就能让人眼感觉是连接的。可是实践上,这个只是针对一般的视频而言。关于一些强交互或许较为敏感的场景来说,比方游戏,起码需求 60 帧,30 帧的游戏会让人感觉不适;位移或许大幅度动画 30 帧会有显着顿挫感;跟手动画假如能到 90 帧乃至 120 帧,会让人感觉十分细腻,这也是近来厂商主打高刷牌的原因。
关于用户来说,从体感视点大致能够将卡顿分为以下几类:
这些体会关于用户能够说是非常糟糕的,乃至会引起感官的烦躁,进而导致用户不愿意持续逗留在咱们的 App。能够说,流通的体会关于用户来说至关重要。
4.2 为什么会发生卡顿
用户体感的卡顿问题原因许多,且常常是一个复合型的问题,为了聚焦,这儿暂只考虑真正意义上的掉帧卡顿。
4.2.1 绕不开的 VSYNC
咱们一般会说,屏幕的刷新率是 60 帧,需求在 16ms 内做完一切的操作才不会形成卡顿。可是这儿需求清晰几个根本问题:
- 为什么是 16ms?
- 16ms 内都需求完结什么?
- 体系怎么尽力确保使命在 16ms 内完结?
- 16ms 内没有完结,必定会形成卡顿吗?
这儿先答复第一个问题:为什么是 16ms。前期的 Android 是没有 vsync 机制的,CPU 和 GPU 的合作也比较混乱,这也形成著名的 tearing 问题,即 CPU/GPU 直接更新正在显现的屏幕 buffer 形成画面撕裂。后续 Android 引进了双缓冲机制,可是 buffer 的切换也需求一个比较适宜的机遇,也便是屏幕扫描完上一帧后的机遇,这也便是引进 vsync 的原因。
早先一般的屏幕刷新率是 60fps,所以每个 vsync 信号的间隔也是 16ms,不过跟着技能的更迭以及厂商关于流通性的追求,越来越多 90fps 和 120fps 的手机面世,相对应的间隔也就变成了 11ms 和 8ms。
那已然有了 VSYNC,谁在消费 VSYNC?其实 Android 的 VSYNC 顾客有两个,也就对应两类 VSYNC 信号,分别是 VSYNC-app 和 VSYNC-sf,所对应的也是上层 view 制作和 surfaceFlinger 的组成,详细的咱们接下来详细说。
这儿还有一些比较有意思的点,有些厂商会有 vsync offset 的规划,App 和 sf 的 vsync 信号之间是有偏移量的,这也在必定程度上使得 App 和 sf 的协同效应更好。
4.2.2 View 颠沛流离的一生
在讲下一 part 之前先引进一个话题:
一个 view 究竟是怎么显现在屏幕上的?
咱们一般都比较了解 view 烘托的三大流程,可是 view 的烘托远不止于此:
此处以一个通用的硬件加快流程来表征
- Vsync 调度:许多同学的一个认知误区在于认为 vsync 是每 16ms 都会有的,可是其实 vsync 是需求调度的,没有调度就不会有回调;
- 音讯调度:首要是 doframe 的音讯调度,假如音讯被堵塞,会直接形成卡顿;
- input 处理:触摸事情的处理;
- 动画处理:animator 动画履行和烘托;
- view 处理:首要是 view 相关的遍历和三大流程;
- measure、layout、draw:view 三大流程的履行;
- DisplayList 更新:view 硬件加快后的 draw op;
- OpenGL 指令转化:制作指令转化为 OpenGL 指令;
- 指令 buffer 交流:OpenGL 的指令交流到 GPU 内部履行;
- GPU 处理:GPU 对数据的处理进程;
- layer 组成:surface buffer 组成屏幕显现 buffer 的流程;
- 光栅化:将矢量图转化为位图;
- Display:显现操控;
- buffer 切换:切换屏幕显现的帧 buffer;
Google 将这个进程划分为:其他时刻/VSync 推迟、输入处理、动画、测量/布局、制作、同步和上传、指令问题、交流缓冲区。也便是咱们常用的 GPU 严厉形式,其实道理是相同的。到这儿,咱们也就答复出来了第二个问题:16ms 内都需求完结什么?
准确地说,这儿仍能够进一步细化:16ms 内完结 APP 侧数据的出产;16ms 内完结 sf layer 的组成
View 的视觉作用正是经过这一整条杂乱的链路一步步展示出来的,有了这个条件,那就能够得出一个定论:上述恣意链路发生卡顿,均会形成卡顿。
4.2.3 出产者和顾客
咱们再回到 Vsync 的话题,消费 Vsync 的双方分别是 App 和 sf,其间 App 代表的是出产者,sf 代表的是顾客,两者交付的中心产品则是 surface buffer。
再详细一点,出产者大致能够分为两类,一类是以 window 为代表的页面,也便是咱们平时所看到的 view 树这一套;另一类是以视频流为代表的能够直接和 surface 完结数据交流的来历,比方相机预览等。
关于一般的出产者和顾客形式,咱们知道会存在相互堵塞的问题。比方出产者速度快可是顾客速度慢,亦或是出产者速度慢顾客速度快,都会导致整体速度慢且形成资源浪费。所以 Vsync 的协同以及双缓冲乃至三缓冲的作用就体现出来了。
思考一个问题:是否缓冲的个数越多越好?过多的缓冲会形成什么问题?
答案是会形成另一个严峻的问题:lag,响应推迟
这儿结合 view 的一生,咱们能够把两个流程合在一同,让咱们的视角再高一层:
4.2.4 机制上的维护
这儿咱们来答复第三个问题,从体系的烘托架构上来说,机制上的维护首要有几方面:
- Vsync 机制的协同;
- 多缓冲规划;
- surface 的供给;
- 同步屏障的维护;
- 硬件制作的支持;
- 烘托线程的支持;
- GPU 组成加快;
这些机制上的维护在体系层面最大程度地保证了 App 体会的流通性,可是并不能帮咱们完全处理卡顿。为了供给愈加流通的体会,一方面,咱们能够加强体系的机制维护,比方 FWatchDog;另一方面,需求咱们从 App 的视点入手,办理运用内的卡顿问题。
4.2.5 再看卡顿的成因
经过上面的讨论,咱们得出一个卡顿剖析的中心理论支撑:烘托机制中的任何流通进程发生反常,均会形成卡顿。
那么接下来,咱们逐一剖析,看看都会有哪些原因或许形成卡顿。
烘托流程
- Vsync 调度:这个是起始点,可是调度的进程会经过线程切换以及一些委派的逻辑,有或许形成卡顿,可是一般或许性比较小,咱们也根本无法介入;
- 音讯调度:首要是 doframe Message 的调度,这便是一个一般的 Handler 调度,假如这个调度被其他的 Message 堵塞发生了时延,会直接导致后续的一切流程不会被触发。这儿直播建立了一个 FWtachDog 机制,能够经过优化音讯调度到达插帧的作用,使得界面愈加流通;
- input 处理:input 是一次 Vsync 调度最先履行的逻辑,首要处理 input 事情。假如有许多的事情堆积或许在事情分发逻辑中加入许多耗时事务逻辑,会形成当时帧的时长被拉大,形成卡顿。抖音根底技能同学也有测验过事情采样的计划,削减 event 的处理,取得了不错的作用;
- 动画处理:首要是 animator 动画的更新,同理,动画数量过多,或许动画的更新中有比较耗时的逻辑,也会形成当时帧的烘托卡顿。对动画的降帧和降杂乱度其实处理的便是这个问题;
- view 处理:首要是接下来的三大流程,过度制作、频繁刷新、杂乱的视图作用都是此处形成卡顿的首要原因。比方咱们平时所说的下降页面层级,首要处理的便是这个问题;
- measure/layout/draw:view 烘托的三大流程,由于触及到遍历和高频履行,所以这儿触及到的耗时问题均会被放大,比方咱们会降不能在 draw 里边调用耗时函数,不能 new 对象等等;
- DisplayList 的更新:这儿首要是 canvas 和 displaylist 的映射,一般不会存在卡顿问题,反而或许存在映射失利导致的显现问题;
- OpenGL 指令转化:这儿首要是将 canvas 的指令转化为 OpenGL 的指令,一般不存在问题。不过这儿却是有一个能够探究的点,会不会存在一类特别的 canvas 指令,转化后的 OpenGL 指令耗费比较大,进而导致 GPU 的损耗?有了解的同学能够探讨一下;
- buffer 交流:这儿首要指 OpenGL 指令集交流给 GPU,这个一般和指令的杂乱度有关。一个有意思的事儿是这儿一度被咱们作为线上收集 GPU 目标的数据源,可是由于多缓冲的要素数据准确度不行被放弃了;
- GPU 处理:望文生义,这儿是 GPU 对数据的处理,耗时首要和使命量和纹路杂乱度有关。这也便是咱们下降 GPU 负载有助于下降卡顿的原因;
- layer 组成:这儿首要是 layer 的 compose 的作业,一般触摸不到。偶尔发现 sf 的 vsync 信号被 delay 的状况,形成 buffer 供给不及时,暂时还不清楚原因;
- 光栅化/Display:这儿暂时疏忽,底层体系行为;
- Buffer 切换:首要是屏幕的显现,这儿 buffer 的数量也会影响帧的整体推迟,不过是体系行为,不能干预。
视频流
除了上述的烘托流程引起的卡顿,还有一些其他的要素,典型的便是视频流。
- 烘托卡顿:首要是 TextureView 烘托,textureview 跟从 window 共用一个 surface,每一帧均需求一同协同烘托并相互影响,UI 卡顿会形成视频流卡顿,视频流的卡顿有时分也会形成 UI 的卡顿;
- 解码:解码首要是将数据流解码为 surface 可消费的 buffer 数据,是除了网络外最重要的耗时点。现在咱们一般都会采用硬解,比软解的功能高许多。可是帧的杂乱度、编码算法的杂乱度、分辨率等也会直接导致解码耗时被拉长;
- OpenGL 处理:有时会对解码完结的数据做二次处理,这个假如比较耗时会直接导致烘托卡顿;
- 网络:这个就不再赘述了,包含 DNS 节点优选、cdn 服务、GOP 配置等;
- 推流反常:这个归于数据源出了问题,这儿暂时以用户侧的视角为主,暂不讨论。
2.5.3 体系负载
- 内存:内存的吃紧会直接导致 GC 的添加乃至 ANR,是形成卡顿的一个不可忽视的要素;
- CPU:CPU 对卡顿的影响首要在于线程调度慢、使命履行的慢和资源竞赛,比方降频会直接导致运用卡顿;
- GPU:GPU 的影响见烘托流程,可是其实还会间接影响到功耗和发热;
- 功耗/发热:功耗和发热一般是不分家的,高功耗会引起高发热,进而会引起体系维护,比方降频、热缓解等,间接的导致卡顿。
4.2.6 卡顿的分类
咱们此处再整体整理并归类,为了更齐备一些,这儿将推流也放了上来。在必定程度上,咱们遇到的一切卡顿问题,均能在这儿找到理论依据,这也是辅导咱们优化卡顿问题的理论支撑。
4.3 怎么点评卡顿
4.3.1 线上目标
目标 | 释义 | 核算办法 | 数据来历 |
---|---|---|---|
FPS | 帧率 | 取 vsync 到来的时刻为起点,doFrame 履行完结的事情为结尾,作为每帧的烘托耗时,一起利用烘托耗时/刷新率能够得出每次烘托的丢帧数。平均 FPS = 一段时刻内烘托帧的个数 * 60 / (烘托帧个数 + 丢帧个数) | vsync |
stall_video_ui_rate | 总卡顿率 | (UI 卡登时长 + 流卡登时长) / 收集时长 | vsync |
stall_ui_rate | UI 卡顿率 | 【> 3 帧】UI 卡登时长 / 收集时长 | vsync |
stall_video_rate | 流卡顿率 | 流卡登时长 / 收集时长 | vsync |
stall_ui_slight_rate | 细微卡顿率 | 【3 – 6】帧丢帧时长 / 收集时长 | vsync |
stall_ui_moderate_rate | 中等卡顿率 | 【7 – 13】帧丢帧时长 / 收集时长 | vsync |
stall_ui_serious_rate | 严峻卡顿率 | 【> 14】帧丢帧时长 / 收集时长 | vsync |
4.3.2 线下目标
Diggo 是字节自研的一个开放的开发调试东西渠道,是一个集「点评、剖析、调试」为一体的,一站式东西渠道。内置功能测评、界面剖析、卡顿剖析、内存剖析、溃散剖析、即时调试等根底剖析能力,可为产品开发阶段供给强大助力。
目标 | 释义 | 核算办法 | 数据来历 |
---|---|---|---|
FPS | 机遇烘托帧率 | 数据获取时刻周期内,实践烘托帧数/ 数据获取间隔时刻 | SF & GFXInfo |
RFPS | 相对帧率 | 数据获取时刻周期内,(理论满帧-实践掉帧数)/ 数据获取间隔时刻 | GFXInfo |
Stutter | 卡顿率 | 卡顿比。当发生 jank 的帧的累计时长与区间时长的比值。 | SF |
Janky Count | 一般卡顿次数 | 单帧制作耗时大于 MOVIE_FRAME_TIME 时,计一次 janky。 | SF |
Big Janky Count | 严峻卡顿次数 | 单帧制作耗时大于 3*MOVIE_FRAME_TIME 时,计一次 big janky。 | SF |
4.4 怎么优化卡顿
4.4.1 常用的东西
线上东西
名称 | 释义 |
---|---|
正式包慢函数 | 相关于灰度包,过滤了比较多监控,对功能损耗比较小,可是需求手动翻开,单点反应中不能保存反应现场 |
灰度包慢函数 | 灰度上全量翻开,针对版别间的数据比照和新增卡顿问题处理比较有用 |
ANR | ANR 的及时响应和处理 |
线下东西
东西名 | 备注 |
---|---|
Systrace | 暂不赘述 |
perfetto | 加强版 systrace,可定制,能够参考官方文档 |
Rhea | 最常用也是最好用的东西,便利发现下下问题和归因,和 perfetto 一同运用绝配,感兴趣的同学能够移步 github 搜索 btrace |
profiler | Androidstudio 自带东西,比较便利,可是数据准确度不高 |
sf / gfxinfo | 首要用于脚本和东西 |
4.4.2 常用的思路
这儿首要针对 UI 卡顿和 UI/流相互影响打来的卡顿。
关于 UI 卡顿来说,咱们手握卡顿优化的 8 板大斧子,所向披靡:
- 下线代码;
- 削减履行次数;
- 异步;
- 打散;
- 预热;
- 复用;
- 计划优化;
- 硬件加快;
整体思路便是「能不干就不干、能少干就少干、能早点干就早点儿干、能晚点儿干就晚点儿干、能让他人干就让他人干、能干完一次当 10 次就只干一次,真实不行,再考虑自己大干一场」。
这儿例举出一些常见的优化思路,留意这必定也不或许是全部,假如有其他好的优化思路,咱们能够一同交流。
4.4.3 一些做过的事儿
处理 UI 卡顿引起的流卡顿
直播关于 SurfaceView 的切换是一个长时间的专项,分为多期逐渐将 SurfaceView 在直播全量落地,场景覆盖秀场直播、聊天室、游戏直播、电商直播、媒体直播等,事务上关于浸透率和逗留时长有比较显着的收益,一起功耗的收益也很可观。
这儿是一个权衡的问题,SurfaceView 的兼容性问题 pk 带来的收益是否能打平,一般来说,越是杂乱的事务场景,收益约大。
处理 message 调度
FWatchDog 是基于对 MessageQueue 的调度策略和同步屏障原理,以均帧耗时为阈值断定丢帧后主动在 MessageQueue 中插入同步屏障,确保烘托异步 message 和 doframe 的优先履行,到达一种烘托插帧的作用,一起具备 ANR 自动康复同步屏障的能力,保证打散的有用。
所以 FWatchDog 和打散是好的伙伴,能发生 1+1 大于 2 的作用。
削减履行次数
一个典型的运用场景便是滑动场景的 GC 抑制,能够显着进步用户上下滑的运用体会。这个场景信任每个事务都会存在,特别是存在许多遍历的逻辑,优化作用显着。
代码下线
一些老的结构、无用的逻辑以及存在性不高的代码都能够下线,这儿根本事务强相关,就不举详细的例子了。
处理耗时函数(打散/异步)
首先是打散,直播做了许多 task 的拆分以及打散,第一能够减轻当时烘托帧的耗时压力,第二能够和 FWatchDog 结合到达插帧的作用。这儿其实还能够操控 task 的履行优先级,包含队列的插队等,总归 MessageQueue 的合理调度是很有必要的。
异步的运用也相比照较多,一个埋点日志的结构,以及一些 inflate 的加载等,都能够运用异步来处理卡顿问题。
预热
直播供给了一个预热结构,能够让直播内部的一次性成本逻辑得到在宿主侧履行的时机,一起供给齐备的队列优先级办理、同步异步办理和 task 生命周期办理,下降直播内部首次加载的卡顿问题。
硬件加快
拉高硬件的运转功能,比方 CPU 频率、GPU 频率、线程绑大核以及网络相关的调优,从底层进步 App 的运转体会。