误区:花费90%的精力去解决10%的性能优化
目标:花20%的精力去解决80%的关键性能优化
启动慢(启动时间优化),卡顿(渲染优化)
启动慢大部分是因为卡顿,根据测试标准不同,也可能是因为动画或者通知UI线程更新的时间点晚了,比如延时显示某个View
卡顿的主要原因是UI线程被阻塞,当绘制一帧超过16ms,将发生丢帧,当丢帧超过30帧时,Choreographer将打印log提示:
Skipped xx frames! The application may be doing too much work on its main thread.
60 * 16 = 960ms 60fps流畅
冷启动是需要优化onCreate和onResume的过程
热启动是需要优化onResume的过程
起点:ActivityManager_activity: startActivityMayWait
终点:ActivityManager: EVENT_APP_ACTIVITY_DISPLAYED_FINISH reportData:
adb shell am start -W -S <包名/完整类名>
起点:ActivityManager_activity: startActivityMayWait
终点:WindowManager: finishDrawingWindow
1.使用ViewStub延迟加载
2.如果使用fragment可以分步载入,不要一次全部显示
3.非UI事务放到子线程或者使用handler延迟执行
4.简化初始化的流程,优化UI布局
场景:
1.绘制的层级深、页面复杂
2.数据处理:UI线程处理数据,数据处理线程繁忙抢占CPU
3.频繁GC
使用Merge标签(减少层级)
RelativeLayout避免嵌套,LinearLayout避免使用权重(https://blog.csdn.net/l_215851356/article/details/56695722)
考虑使用ConstraintLayout
使用ViewStub
如果有确定值,避免wrap_content
避免数据处理卡主线程
多线程带来的内存问题
有时候为了性能,会把一个操作抛到子线程,很多时间写起来方便,就直接通过写new Thread(){…}.start();的方式来实现,这种方式每次都创建一个Thread,压力测试时可能会短时间内创建大量线程,如果是网络请求,还会产生大量socket链接,内存开销大,可能产生OOM。
有的使用线程池,但是使用cached或者fixed等Executors创建出来简单的线程池,没有设置拒绝策略,如果大量地加到线程池中,阻塞队列无限增加,也可能产生OOM。
还有一种使用ThreadHandler,在应用退出时HandlerThread没有quit,导致HandlerThread不能释放,产生内存泄露,长时间压力测试可能出现OOM。
高内存带来的性能问题
当内存很低,不足以分配给新对象时,会触发GC,这个耗时会引起实际执行时间的增加,比如当load一张特别大的图片时候就可能触发GC,这时候就会发生卡顿。
所以性能问题和内存问题是相关的,但性能问题中很多时候都伴随着内存问题,在解决性能问题的时候要考虑会不会引入内存问题,修改问题时需要选择一个让两者都高效折中值。
资源使用未关闭
注册广播,listener未注销
非静态内部类滥用
单例滥用
Handler阻塞
使用Android device monitor,Android profiler分析
非正常使用的情况:
1.调用了wakelock没有释放
2.某个高优先级的进程对某个低优先级进程的Service设置了死亡后重启,当低内存的情况,低优先级的service不停地被系统杀掉,高优先级的进程不停地收到回调,重新拉起servie并做一些初始化操作。
3.进程中起了一个永远不会停的操作,如使用百度定位sdk,启动了,成功定位后没有关掉,导致一直循环定位。
4.误操作的终止条件太高。如语音误唤醒,语音唤醒分两次,第一次会做一些初始化操作来提速,等第二次真正唤醒后再拉起界面,如果第二次确认是误唤醒就销毁。如果初始化过程不能有效被打断,销毁过程将被滞后,导致每次误唤醒都是一次完整的初始化和销毁。原本从第一次唤醒到确认是误唤醒只有2s,但是等到真正整个过程终止可能要花10s甚至半分钟,功耗成几十倍增长。
《Android移动性能实战》(腾讯SNG专项测试团队 编著)
http://www.cnblogs.com/cr330326/p/8011523.html
https://blog.csdn.net/yingshukun/article/details/79304817
熟悉业务
理解原理
大胆猜测
动手验证