Google近期在Udacity上发布了Android性能优化的在线课程,分别从渲染,运算与内存,电量几个方面介绍了如何去优化性能,这些课程是Google以前在Youtube上发布的Android性能优化典范专题课程的细化与补充。html
下面是内存篇章的学习笔记,部份内容与前面的性能优化典范有重合,欢迎你们一块儿学习交流!java
众所周知,与C/C++须要经过手动编码来申请以及释放内存有所不一样,Java拥有GC的机制。Android系统里面有一个Generational Heap Memory的模型,系统会根据内存中不一样的内存数据类型分别执行不一样的GC操做。例如,最近刚分配的对象会放在Young Generation区域,这个区域的对象一般都是会快速被建立而且很快被销毁回收的,同时这个区域的GC操做速度也是比Old Generation区域的GC操做速度更快的。android
除了速度差别以外,执行GC操做的时候,全部线程的任何操做都会须要暂停,等待GC操做完成以后,其余操做才可以继续运行。性能优化
一般来讲,单个的GC并不会占用太多时间,可是大量不停的GC操做则会显著占用帧间隔时间(16ms)。若是在帧间隔时间里面作了过多的GC操做,那么天然其余相似计算,渲染等操做的可用时间就变得少了。app
Android Studio中的Memory Monitor能够很好的帮助咱们查看程序的内存使用状况。工具
内存泄漏表示的是再也不用到的对象由于被错误引用而没法进行回收。性能
发生内存泄漏会致使Memory Generation中的剩余可用Heap Size愈来愈小,这样会致使频繁触发GC,更进一步引发性能问题。学习
举例内存泄漏,下面init()方法来自某个自定义View:优化
private void init() { ListenerCollector collector = new ListenerCollector(); collector.setListener(this, mListener); }
上面的例子容易存在内存泄漏,若是activity由于设备翻转而从新建立,自定义的View会自动从新把新建立出来的mListener给绑定到ListenerCollector中,可是当activity被销毁的时候,mListener却没法被回收了。动画
下图演示了Android Tools里面的Heap Viewer的功能,咱们能够看到当前进程中的Heap Size的状况,分别有哪些类型的数据,占比是多少。
Memory Churn内存抖动,内存抖动是由于在短期内大量的对象被建立又立刻被释放。瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,会触发GC从而致使刚产生的对象又很快被回收。即便每次分配的对象占用了不多的内存,可是他们叠加在一块儿会增长Heap的压力,从而触发更多其余类型的GC。这个操做有可能会影响到帧率,并使得用户感知到性能问题。
解决上面的问题有简洁直观方法,若是你在Memory Monitor里面查看到短期发生了屡次内存的涨跌,这意味着颇有可能发生了内存抖动。
同时咱们还能够经过Allocation Tracker来查看在短期内,同一个栈中不断进出的相同对象。这是内存抖动的典型信号之一。
当你大体定位问题以后,接下去的问题修复也就显得相对直接简单了。例如,你须要避免在for循环里面分配对象占用内存,须要尝试把对象的建立移到循环体以外,自定义View中的onDraw方法也须要引发注意,每次屏幕发生绘制以及动画执行过程当中,onDraw方法都会被调用到,避免在onDraw方法里面执行复杂的操做,避免建立对象。对于那些没法避免须要建立对象的状况,咱们能够考虑对象池模型,经过对象池来解决频繁建立与销毁的问题,可是这里须要注意结束使用以后,须要手动释放对象池中的对象。
关于Allocation Tracker工具的使用,不展开了,参考下面的连接:
下面演示一个例子,如何经过修改代码来避免内存抖动。优化以前的内存检测图:
定位代码以后,修复了String拼接的问题:
优化以后的内存监测图:
上面提到了三种测量内存的工具,下面再简要归纳一下他们各自的特色: