正文
Android性能优化对于开发者来说是一个不可小觑的问题,如果软件的性能极差,造成界面卡顿,甚至直接挂掉,对于用户来说是一个极其致命的,可能会导致用户直接把应用给卸载了。相反的,如果把性能优化得极致,运行得很流畅,从而增加用户的好感,得到好评,所以性能优化对于开发者来说是非常重要的。
Android的性能优化通常涉及到内存泄露检测、渲染性能优化、电量优化、网络优化和Bitmap内存管理优化,以及多线程优化等等,当然性能优化的不止这些,除此之外还有安装包优化和数据传输效率等,所以Android的性能优化涉及的范围是比较广的。心急吃不了热豆腐,因此需要我们一点点来学习,慢慢研究。
内存泄露
内存泄露,关乎到开发者本身写代码的问题,所以平时开发者写代码要有严谨性和清晰的逻辑,申请的内存,没用之后,就要释放掉。那么什么是内存泄露呢?
了解内存泄露,首先需要了解java的内存分配,其中主要包括静态存储区、栈区、堆区、寄存器、常量池等。
静态存储区:内存在程序编译的时候就已经分配好,这块的内存在程序整个运行期间都一直存在,主要存放静态数据、全局的static数据和一些常量。
栈区:保存局部变量的值,其中包括:用来保存基本数据类型的值、保存类的实例(即堆区对象的引用(指针)),以及用来保存加载方法时的帧。也就是说函数一些内部变量的存储在栈区,函数执行结束的时,这些存储单元就会自动被释放掉。因为栈内存内置在处理器的里面,所以运算速度很快,但是栈区的容量有限。
堆区:也叫做动态内存分配,用来存放动态产生的数据,如new出来的对象。用malloc或者new来申请分配一个内存。在C/C++可能需要自己负责释放,但在java里面直接依赖GC机制。
寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。
常量池:存放常量。
关于内存分配,读者可以参考
《Java 内存分配全面浅析》
栈和堆的区别:
1)堆是不连续的内存区域,堆空间比较灵活也特别大。
2)栈式一块连续的内存区域,大小是由操作系统决定的。
由于堆是不连续的内存区域,管理起来特别的麻烦,如果频繁的new和remove,可能会造成大量的内存碎片,所造成的内存碎片就造成了内存泄露,这样就会导致运行效率低下。但是对于栈,栈的特点是先进后出,进出完全不会产生碎片,运行效率高且稳定。因此我们关于内存泄露,主要看堆内存。
内存泄露(memory leak):是指程序在申请内存后,无法释放已申请的内存空间。也就是说当一个对象已经不再使用了,本该被回收时,但有另外一个正在使用的对象持有它的引用从而就导致对象不能被回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏。
内存溢出
内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory。在Android中如果出现内存溢出,也就是我们经常看到的OOM情况,那么应用就会闪退。由于内存泄露,而导致可用的内存空间越来越少,从而导致OOM。因此平时写代码特别需要主要内存泄露的情况,因为一旦出现内存泄露,随着泄露的内存越来越多,就会造成内存溢出。
既然是内存泄露会导致内存溢出,归根结底还是需要优化内存泄露。优化内存泄露,首先需要找到内存泄露的地方,然后才能去优化。
确定内存泄露
1)使用AndroidStudio自带的Memory Monitors进行内存分析。
通过可视化可以观察到该应用的Memery、CPU、NetWork和GPU变化等情况。这里我们主要观察Memery(内存)即可,上图是我打开应用的首页时Memery的情况。
然后点击几次InitiateGC:
这是点击GC之后,稳定下来的情况,基本上时一条水平线的状态的了。
Free:表示还可用的内存,在图中浅灰色表示。
Allocated:表示已经分配的内存大小,同样在图中蓝色表示
当我进入下个页面的时候,明显看到内存变化
当我返回上一个页面的时候,然后GC
上图就是返回之后,点击GC的情况,Free和Allocated并没有变化,说明刚刚进入的那个页面就没有出现内存泄露的情况,如果出现变化比较明显,那就可以判断刚刚所进入的页面出现了内存泄露的情况。同样也可以使用Heap Viewer观察内存泄露。
Heap Viewer
Heap Viewer:能够实时查看App分配的内存大小和空闲内存大小,并发现内存泄露。除此功能以外,Heap Viewer还可以检测内存抖动,因为内存抖动的时候,会频繁发生GC,这个时候我们只需要开启Heap Viewer,观察数据的变化,如果发生内存抖动,会观察到数据在短时间内频繁更新。
启动Heap Viewer:
选择设备下对应的包名,然后update Heap
选择Head,然后GC
点击Cause GC,发现所有的数据都更新了,更新后的表格显示,在Heap上哪些数据是可用的,选中其中任一行数据,就可以看到详细数据。
data object的total size就是当前进程中Java的对象所占用的内存总量。我们反复执行某一个操作并同时执行GC排除可以回收掉的内存,注意观察data object的Total Size值,正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况。反之如果代码中存在没有释放对象引用的情况,随着操作次数的增多Total Size的值会越来越大。
点击class object,屏幕上马上出现大量更新的数据,矩形图列出这一数据内存分配的数量,以及确切的容量,heap viewer可以有效地分析程序在堆中所分配的数据类型,以及数量和大小。
Allocation Tracker
除了Head Viewer和Memory Monitor,还可以使用Allocation Tracker(分配追踪器)。
关于Allocation Tracker可以查看
《Android性能专项测试之Allocation Tracker(Android Studio)》
这篇文章进行学习。
以上的工具都具有不同的特点,具体使用那一个工具可以按照以下来划分:
1)Memory Monitor:获得内存的动态视图
2)Heap Viewer:显示堆内存中存储了什么
3)Allocation Tracker:具体是哪些代码使用了内存
使用MAT内存分析工具
MAT:Memory Analyzer Tools,一款详细分析Java堆内存的工具,从而能够分析出内存泄露的详细情况。