Android性能优化 | 青训营笔记

256 阅读5分钟

这是我参与「第四届青训营」笔记创作活动的第8天。

本笔记内容是第七课的Android性能优化。

1 为什么要做性能优化

1.1 从用户体验和业务来看

性能优化可以改善用户体验,有助于提升业务指标。

1.2 从更长时间范围来看

  • 硬件性能提升速度变缓;

  • 多核带来的提升取决于真正可以并行执行的部分;

  • 移动处理器受电池容量限制;

  • 软件还有优化空间。

2 性能优化是什么

性能优化的总目标是快、稳、省。

2.1 流畅性优化

2.1.1 了解Android线程结构

在Main Thread UI线程中包括:

System Events

Input Events

Application

Services

Alarm

UI Drawing (系统控制 与App代码无关)

SurfaceFlinger VSync信号  16ms一次或更小

肉眼感知到不卡顿的最低帧数是25。如果没有VSync信号,会导致画面撕裂。

2.1.2 卡顿感知产生原因示例

输入事件无法及时响应,“划不动”

输入事件耗时太长,丢帧

其它事务LameWork,丢帧

解决卡顿:将耗时操作放到其它线程操作

2.2 资源优化

资源:即Android手机的软硬件资源,通俗意义上应用依赖的移动终端的有限资源和系统设置的数值

资源优化方向:

  • 端侧资源(功耗、内存、存储、CPU、GPU、网络、音量、亮度等)应用色系和应用亮度带来功耗差异
  • 服务侧资源(CDN带宽、API流量)

2.3 稳定性优化

稳定性分为崩溃和超时。超时可导致卡顿掉帧和ANR。其中最关注的是ANR。

2.4 系统级优化

移动操作系统和硬件厂商的性能优化

2014年

ZRAM 无效内存压缩 合入Android主分支

Render Script GPU优化

2015年

推出Android Runtime(ART)虚拟机

HMP scheduler解决大小核问题

2016年

sdcardFS:针对SD卡的优化

CPUset group:前后台应用的限制

2017年

SKGL&Vulkan:图形处理

F2FS:新的文件系统

ART profile and image:计算更精确

Binder refactor

2018年

Cloud profile:Google Play运控

Odex relayout

EAS调度器:平衡功耗与性能

2019年

Generational Concurrent Copying GC:分代并行拷贝GC,提升GC性能  

3 最佳工具选型

3.1 性能监控的价值

·监控和优化相生相伴

·监控有攻有防,攻是未来发现现有问题,指导优化方向;防是为了发现劣化问题及时止损

·线上监控发现问题并聚合排序,线下监控作为线上辅助,并在发版前置发现解决问题

3.2 GPU呈现模式

系统通过记录每一帧的相关数据,然后通过图形的形式呈现。

无需二次开发,简单易用,但并不完全准确,并且无法明确造成卡顿原因

3.3 Layertool

找到过度绘制的布局。

通过遍历ViewTree信息,输出View层级关系。

清楚明了,可以宏观感知ViewTree现状,也可以定制,帮助分析overdraw。但不能明确UI性能瓶颈。

3.4 CPU Profiler

Android Studio里有,基于JVMTI(只能在Debug版App执行)

优点:完整的方法调用栈输入、支持Java、C、C++方法耗时检测,上手简单,但性能损耗太大。

3.5 TraceView

Instrument:虚拟监听函数入口回调,Enter/Exit/Unwind

耗时点:读时间、写数据到buffer、加锁等

Sample:定时抓取多次堆栈diff,近似确定函数的进入和退出时间

耗时点:堆栈diff、同Instrument

间隔抓取堆栈的时间越长性能损耗越少,但是同时越容易导致短函数不能被检测到

3.6 Systrace

重要工具

ftrace:debugfs采集和读取trace数据,记录trace events

atrace:用户侧的trace跟踪,聚合所有的trace event。

系统级的Trace数据:锁监控等

3.7 btrace(aka rhea) (进阶)

rhea-systrace:全函数插桩,自动生成Trace代码,对层数做限制,性能损耗50%

rhea-mtrace:全函数插桩,抛弃systrace,自己统计函数耗时,数据展现与systrace相同

rhea-atrace:优化systrace性能,聚合更多性能数据,如类加载、Lock、IO等

3.8 Battery Historian

安装到电脑

手机充满电或者reset batterystats,并在手机上执行测试应用,抓取bugreport

电脑分析bugreport

4 案例

4.1 现状分析

CPU Time

循环,反射,序列化/反序列化,类解析

IO Wait

IO操作,等待IO返回结果

IPC

Binder调用耗时 

Lock Wait

主线程是等锁状态,等待其他线程或自己超时唤醒

CPU Schedule

主线程是可执行状态,但是获取不到CPU时间片 

运行环境归因

根据耗时成因归类。根据运行所在线程环境采用不同的策略。

Cold Start 目标:小于3秒

Create process

ContentProvider init

Application#Create

Warm Start 目标:小于1秒

Activity#Create

Inflate view hierarchy

Hot Start

Activity#onStart()

渲染分析

渲染瓶颈:

渲染耗时 inflater init bind measure/layout/draw overdraw

渲染频率 Animator FPS,Vsync Leak,requestlayout loop

 

4.2 优化策略及案例

UI创建

耗时成因:XML IO,Class反射,创建View,Asset资源大锁

官方解决方案:AsyncLayoutInflater

抖音解决方案:

AndInflater:解决xml性能问题-外界方案X2C

LegoInflate:高优先级的启动预加载方案

AsyncInflater:随时随地预加载,不与具体逻辑绑定,生命周期存活,自定义清理周期

数据请求+解析:

GSON解析优化 是否服用gson对象有较大差异

数据协议优化 json->protobuf

渲染耗时优化:

移除不必要的背景图;修改不合理布局;写高效合理的布局;移除默认的Window背景,绘制层级优化

异步渲染:

SurfaceView:采用独立的线程进行绘制和渲染,生命周期需要自己控制

Jetpack Compose:基于组合优于继承的思想,重新设计一套解耦的UI框架

Litho:复杂UI下的高性能渲染框架

5 总结

本节课介绍了Android性能优化的现状、工具,为Android客户端性能优化方向的进一步学习奠定了基础、提供了方向。