这是我参与「第四届青训营 」笔记创作活动的第7天
本节课的主要内容:初识性能优化及工具
1,为什么要做性能优化
- 性能优化带来体验的改善,进而帮助业务指标的提升
- 从更长的时间范围来看,硬件性能提升速度变缓,ARM平台收益于架构和工艺的演进,最近几年趋势比X86平台好。
- 从更长远的时间范围来看,多核带来的提升取决于可以真正并执行的部分。
- 未来,新的材料和工艺会驱动芯片性能的进一步提升,移动处理器还受电池技术的限制,软件性能还可继续优化。
2,性能优化是什么
目标:快 准 省
2.1 流畅性优化
极致的响应与流畅的体验
2.2 资源优化
最小符合带来最大的收益
2.3 稳定性优化
稳定的实现,减少不必要打断
2.4 系统级优化
底层booster
3,最佳工具选型
性能监控的价值
App的性能问题包括崩溃、网络请求错误或超时、响应速度慢、列表滚动卡顿、流量大、耗电等等。而导致App性能低下的原因有很多,除去设备硬件和软件的外部因素,其中大部分是开发者错误地使用线程、锁、系统函数、编程范式、数据结构等导致的。即便是最有经验的程序员,也很难在开发时就能避免所有导致性能低下的“坑”,因此解决性能问题的关键是在于能不能尽早地发现和定位这些“坑”。
GPU呈现模式
**原理: 系统通过记录每一帧的相关数据,然后通过图形的形式呈现。
优点: 无需二次开发,简单易用
缺点: 并不完全准确,且无法明确指出造成卡顿问题的具体原因
Layertool
原理: 通过遍历ViewTree信息,输出View层级关系
优点: 清楚明了,能宏观感知ViewTree现状,也可以定制,帮助分析overdraw
缺点: 还不能清楚明确的分析出UI的性能瓶颈
CPU Profiler
原理: 基于JVMTI
优点: 完整的方法调用栈输出、支持Java、C、C++方法耗时检测、上手简单
缺点: 性能耗损太大
...
4,如何优化
4.1 原因
- CPU Time 指占用CPU进行计算所花费的时间绝对值,中断、挂起、休眠等行为是不会增加CPU Time的,所以因CPU Time开销占比高导致的不合理耗时点往往是逻辑本身复杂冗长需要消耗较多cpu时间片才能处理完。比较常见的高CPU占用是循环,比如抖音启动时遇到过一个so加载耗时,最后定位原因是在解压so的时候,遍历ZipEntry的次数过多导致,一个可行的优化策略就是可以把so所在的ZipEntry提前,遍历完so的ZipEntry之后可以提前中止遍历,而不需要遍历剩下的无效ZipEntry。
- CPU Schedule 在分析时主要针对主线程,是指主线程处于可执行状态但获取不到cpu时间片,这类耗时可能和线程调度等有关,最终导致分配给主线程的cpu时间片不足以及时处理完其内任务。由于主线程的线程优先级比其他线程的优先级要高很多,通常影响并不大,事实上抖音做了线上用户的启动耗时统计,这部分的耗时占比也是不大的。不过有一个场景需要关注,就是渲染,渲染是需要RenderThread提交GPU的渲染命令,而RenderThread并没有主线程那么高的优先级,因此比较容易受CPU的负载的影响,导致渲染耗时。
- IO Wait 指发生了IO操作需要等待IO返回结果,这类耗时可能发生在读取资源和文件,类加载,甚至在内存不足时的PageFault都会导致IO Wait。
- Lock Wait 也是主要针对主线程,指其处于等锁状态,等待被其他线程唤醒或自己超时唤醒,导致这类耗时的问题种类多样,大体也是可以分为业务锁和系统锁,业务锁主要是被主线程等待的业务逻辑未能及时处理完,优化思路一般是移除主线程的锁等待逻辑或者加快被等待的业务逻辑的执行速度。系统锁主要有:String InternTable Lock,ClassLinker Lock,GC Wait Lock等
- IPC 指进程间通信,操作系统大都含有相应的机制,Android中所特有的IPC机制是Binder,由于进行IPC调用往往需要等待通信结果本质上这也算是一种Lock Wait,但Android特有Binder机制所以单独列出,这类耗时可采用减少或替代Binder调用等手段来优化。
4.2 优化案例分享
-
4.2.1 拆解View显示流程中的耗时成因
-
-
UI 构建
- 在UI构建阶段中首先要对界面布局的xml文件进行解析,这会导致IO Wait耗时,在接下来要解析xml文件中的TagName从而获取对应View的class会用到反射、创建各子View实例并生成View树又会用到循环递归,两部分都会增加CPU Time的开销。
-
数据绑定
- 然后是数据绑定阶段,该阶段主要分两部分,一部分是对数据做请求、解析、适配,另一是部分是将适配好的数据填充进UI中,前一部分往往会涉及到Json解析成Data Class实例,这里就可能涉及反射、循环遍历嵌套的数据类结构等增加CPU Time的操作。
-
View显示
- 最后是View显示阶段,常见的measure、layout、draw三大渲染View的步骤就在其中,它们同样会产生递归遍历父子View的耗时,此外这里还涉及将应用层计算好的渲染View的数据传递给系统层做最终的像素点排布,那么必然又会产生IPC耗时
-
4.2.2 UI构建的优化方案
developer.android.com/reference/a…
4.2.3 数据绑定的优化方案
4.2.4渲染和布局优化方案
系统工具查看具体的overdraw情况,但并不能细化到具体的布局和位置,我们开发了LayerTool工具可以根据自定义需求过滤各个布局,然后在界面上提示对应的位置,可以有效的查找导致overdraw的布局。我们通过LayerTool工具查看哪些布局导致了过度绘制。然后我们可以逐个开始优化:
- 移除不必要的背景图 :去除冗余背景
- 修改不合理布局:精细化布局显示
- 写高效合理的布局:随着状态的变换,及时调整布局的绘制背景
- 移除默认的 Window 背景 :Activity其实是有一层默认背景windowBackground。如果需要做到极致的优化,可以考虑将windowBackground设置为空,但是同时需要处理好随之而来的各种问题。主要包括:把windowBackground设置为空后,如果有某些View没有设置背景,就会出现花屏/重影的现象。
4.2.5 渲染优化的异步化方案
如何彻底解决主线程的阻塞问题:
5,总结
本次课程就性能优化问题的2个w与1个h进行讲述,讲解了为什么要性能优化,如何性能优化,举了一些案例来进行分析,讲述了性能优化的重要性以及方法与工具的选择。(更多详情【Android 客户端专场 学习资料三】第四届字节跳动青训营 - 掘金 (juejin.cn))