介绍
卡顿优化方向
耗时操作:异步、延迟
布局优化:异步Inflate、X2C、重绘解决
内存:降低内存占用,减少GC时间
卡顿监控指标
卡顿率、ANR率、秒开率
交互时间、生命周期
上报环境、场景信息
工具
cpu profiler
systruce
方便看出来CPU使用情况,开销小
TruceView
方便看出来每个线程在特定时间在做什么,开销大容易带偏优化方向
StrictMode
严苛模式,Android提供的一种运行时检测机制
方便强大,容易被忽视
包含:线程策略和虚拟机策略检查
线程策略
自定义的耗时调用,detectCustomSlowCalls()
磁盘读取操作,detectDiskReads
网络操作,detectNetwork
虚拟机策略
Activity泄漏,detectActivityLeaks
Sqlite对象泄漏,detectLeakedSqlLiteObjects
检测实例数量,setClassInstanceLimit()
AndroidPerformanceMonitor
github
介绍:非侵入式的性能监控组件,通知形式弹出卡顿信息,方便精确定位
缺点:
确实卡顿了,但卡顿堆栈可能不准确
和OOM一样,最后的堆栈只是表象,不是真正问题
优化方向:获取监控周期内的多个堆栈,而不仅仅是最后一个
ANR-WatchDog
github
非侵入式的监控ANR组件
Lancet
github
轻量级android aop框架
编译速度快,支持增量编译
API简单没有任何多余代码插入APK
@proxy 通常用于对系统API调用的hook
@insert 常用于操作app与library的类
自动化卡顿检测方案及优化
为什么需要自动化检测方案
系统工具适合线下针对性分析
线上及测试环境需要一套自动化检测方案
方案原理
消息处理机制,一个线程只有一个Looper
mLogging对象在每一个message处理前后被调用
主线程发生卡顿,是在dispatchMessage执行耗时操作
具体实现
Looper.getMainLooper().setMessageLogging();
匹配>>>>>Dispatching,阀值时间后执行任务(获取堆栈)
匹配<<<<<Finished,任务启动之前取消掉
AndroidPerformanceMonitor
github
介绍:非侵入式的性能监控组件,通知形式弹出卡顿信息,方便精确定位
缺点:
确实卡顿了,但卡顿堆栈可能不准确
和OOM一样,最后的堆栈只是表象,不是真正问题
优化方向:获取监控周期内的多个堆栈,而不仅仅是最后一个
海量卡顿堆栈处理
高频卡顿上报量太大,服务端有压力
分析:一个卡顿下多个堆栈大概率有重复
解决:对一个卡顿下堆栈进行hash排重,找出重复的堆栈
效果:极大的减少展示量,同时更高效的找到卡顿堆栈
ANR分析
触发分类
KeyDispatchTimeout(按键或触摸事件),5s
BroadcastTimeout,前台10s,后台60s
ServiceTimeout,前台20s,后台200s
ANR执行流程
发生ANR
进程接收异常终止信号,开始写入RNR信息
弹出ANR提示框
ANR解决套路
adb pull data/anr/traces.txt
详细分析:CPU、IO、锁
线上ANR监控方案
通过FileOberver监控文件变化,高版本权限问题
ANR-WatchDog
github
非侵入式的监控ANR组件
原理
子线程 使用handler向主线程发送一条执行数量+1操作的Message,子线程休眠指定时间后,检查数值是否执行过+1操作,如果+1表示未ANR,如果未+1表示已经ANR
监听ANR异常信息
new ANRWatchDog().setANRListener(new ANRWatchDog.ANRListener() {
@Override
public void onAppNotResponding(ANRError error) {
// Handle the error. For example, log it to HockeyApp:
ExceptionHandler.saveException(error, new CrashManager());
}
}).start();
单点问题监测方案
背景介绍
自动化卡顿监测方案并不够
体系化解决方案务必尽早的暴露问题
单点问题:主线程IPC、DB
IPC问题监测
IPC调用类型
调用耗时、次数
调用堆栈、线程
常规方案
IPC前后加埋点
不优雅、容易忘记
维护成本大
IPC问题监测技巧
adb命令:
adb shell am trace-ipc start
adb shell am trace-ipc stop —dump-file /data/local/tmp/ipc-trace.txt
adb pull /data/local/tmp/ipc-trace.txt
优雅方案
ARTHook 还是 AspectJ ?
ARTHook:可以hook 系统级方法
AspectJ:非系统方法
卡顿问题监测方案
利用ARTHook完善线下工具
开发阶段Hook相关操作,暴露、分析问题
监控纬度
IPC
IO、DB
View 绘制
如何实现界面秒开
界面秒开就是一个小的启动优化
可以借鉴启动优化及布局优化章节
实现
Syctrace,优雅异步+优雅延迟初始化
异步Inflate、X2C、绘制优化
提前获取页面数据
界面秒开监控纬度
总体耗时
生命周期耗时
生命周期间隔耗时
页面秒开率统计
onCreate 到 onWindowFocusChanged 为耗时
使用Lance AOP库, 切入onCreate方法获取开始创建时间,切入onWindowFocusChanged获取第一帧显示时间,相减获取到页面创建耗时
public class ActivityHooker {
private static ActivityRecord mActivityRecord;
static {
mActivityRecord=new ActivityRecord();
}
@TargetClass(value = "android.support.v7.app.AppCompatActivity", scope = Scope.LEAF)
@Insert(value = "onCreate", mayCreateSuper = true)
protected void onCreate(){
mActivityRecord.mOnCreateTime=System.currentTimeMillis();
Origin.callVoid();
}
@TargetClass(value = "android.support.v7.app.AppCompatActivity", scope = Scope.LEAF)
@Insert(value = "onWindowFocusChanged", mayCreateSuper = true)
public void onWindowFocusChanged(){
mActivityRecord.mOnWindowFocusChangedTime=System.currentTimeMillis();
Log.d("codytest","onWindowFocusChanged cost:"+(mActivityRecord.mOnWindowFocusChangedTime-mActivityRecord.mOnCreateTime));
Origin.callVoid();
}
}
耗时盲区监控
线下
TraceView
特别适合一段时间的盲区监控
线程具体时间做了什么,一目了然
线上
思考分析
所有方法都是Msg,mLogging?没有Msg具体堆栈
AOP切Handler方法?不清楚准确执行时间
解决方案:
使用统一的Handler:定制具体方法
定制gradler插件,编译期动态替换Handler
总结:
卡顿监控重要的一环,全面性保障
TraceView试用于线下,可以监控系统Msg
动态替换适合线上,只有应用自身的Msg
模拟问题
你是怎么做卡顿优化的
第一阶段:系统工具定位、解决
第二阶段:自动化卡顿方案及优化
第三阶段:线上监控及线下监测工具建设
怎么自动化的获取卡顿信息
mLogging.println
高频采集,找出重复堆栈
卡顿的一整套方案是怎么做的
线下(线下侧重尽早的发现暴露问题)和线上(线上侧重监控的全面性和自动化和异常感知的灵敏度)相结合
特定难题突破:重点问题、盲区监控
线上监控建设