Android性能功耗问题总结

误区:花费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的过程

如何查看冷启动和热启动的耗时?

  • 冷启动:关键log ActivityManager: Displayed可以直接看时间

起点:ActivityManager_activity: startActivityMayWait

终点:ActivityManager: EVENT_APP_ACTIVITY_DISPLAYED_FINISH reportData:

adb shell am start -W -S <包名/完整类名>

 

  • 热启动:关键log onResume

起点: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

 

熟悉业务

理解原理

大胆猜测

动手验证

 

 

你可能感兴趣的:(Android性能功耗问题总结)