Android内存优化之内存泄漏

Android系统的内存泄漏

使用过C/C++的朋友都知道使用对象都需要特别小心,一不留神就会忘记对象内存的释放。Java语言的好处之一就是内存使用大多数时候都不需要自己手动释放,这个直接交给GCch处理。虽然Dalvik虚拟机支持垃圾回收,但是并不意味着我们就可以随便使用内存或者不关心内存的使用情况,在内存紧张的移动设备上,内存的使用尤为重要。

内存泄漏通常是使用者没正确的使用对象或者对象的引用关系没注意导致内存迟迟得不到释放,造成系统卡顿,严重的会导致重启。内存泄漏的产生有很多种情况,通常小的内存泄漏并不会被人为发现或者注意,但当一个应用程序内存泄漏足够多的时候就会导致应用程序崩溃。

严重的内存泄漏情况:

(1)嵌入式或者便携式设备上,因为本身内存有限,内存使用不当会导致严重的后果;

(2)系统关键驱动上,因为频繁调研,会导致系统内存泄漏越来越严重;

(3)系统内部泄漏,Android系统本身也是由代码所成,所以也会存在内存使用不当的情况;

(4)后台程序一直运行,不断消耗内存,导致内存一直高占用率;

(5)游戏视频或者画面频繁的重绘;

(6)等等。

 

为什么会内存泄漏

简单来说就是对象的内存无法被GC所回收探测,GC通过对象可达性或者引用链等方式判断对象的状态,如果当前对象无其他对象引用或者不可达,就会把对象标记为可回收状态,等待被回收。

引用的强弱,可达性的引用级别:

(1)强引用:一般无其他生命都是强引用,级别最高,当内存非常吃紧且只有强引用的时候会GC;

(2)软引用:只要有内存足够,就一直保持对象,一般用于缓存;

(3)弱引用:比软引用更弱,当内存回收时马上回收这部分内存;

(4)虚引用:根本不会在内存中保持的对象,一般用于finalize()方法时进行特殊清理的过程;

据generation进行GC,堆可分为年轻代、老年代、永久代(Java8之后没有永久代,改为Metaspace);

Android内存优化之内存泄漏

(1)年轻代

绝大多数的对象都会分配在年轻代中,同时大部分对象ye也在年轻代中就被回收,其中,年轻代又分为三部分:一个Eden区和两个Survivor区,默认的比例为8:1。从比例上看Eden区分配的比例大,也可以猜测出在Eden区存在的对象会较多,当进行第一次Minor GC时,大部分对象会被回收掉,一些存活下来的对象会迁移到Survivor区,每进行一次Minor GC,这些存活下来的对象都会增加一岁,当第一个Survivor区满了的时候就会把这些存活下来的对象复制到第二个Survivor中,当第二个Survivor区也满了的时候就会把存活下来的对象复制到老年代中。经历了n次GC后存活在laon老年代的对象,我们可以把这些对象视为生命周期长的对象。

(2)老年代

在年轻代经过n次回收存活下来的对象,一般是长生命周期对象;

(3)永久代(持久代或者称为方法区)

一般用于存放静态文件,如今Java类、方法等,持久代对垃圾回收没有显著影响,GC回收的目标仅针对方法区的常量池和类型卸载 ;在JDK8后被元空间(Metaspace)取代;

 

Shallow Size和Retained Size等

要了解对象的存储长度,需要知道对象的Shallow Sizehe和Retained Size,其中Shallow Size我指对象本身占用的内存大小,不包含其他对象的引用(这点很重要);

Shallow Size:Java语言中一切都是对象(除了基本类型外),比如int类型占4字节,String类型中包含三个int成员、一个char[ ]成员、以及一个对象头,所以一个String对象占 3*4+1+4+8 = 24字节,从而可以计算得到相应的内存大小。

Retained Size:指该对象的Shallow Size,外加上该对象能直接或者间接访问到的对象的Shallow Size,简单理解就是该对象引用链的内存之和;

Heap Size:堆栈分配给App的内存大小;

Allocated:以及分配的内存大小,该应用进程所分配到的内存大小,当应用程序被回收或者退出时,该值会相应变小;

 

内存泄漏调试工具

通常来说使用adb可以观察出应用程序是否内存泄漏,但是如果想进一步了解泄漏的详细信息,我们就不得不借助一些工具来分析了。

(1)DDMS工具,adt或者Android studio本身自带的调试工具,可用DDMS生成.hprof文件,然后通过生成几份不同的.hprof文件进行对比,查找出具体泄漏的对象;

(2)MAT:全称为Memory Analyzer Tool,是一款bucu不错的内存分析调试工具,使用MAT分析内存泄漏的思路在于对象的引用关系,分析出具体哪个对象没有被释放,从而对位da到代码当中。MAT的下载地址:http://www.eclipse.org/mat/

(3)Leak Canary:一款第三方库,使用起来非常简单,只要依赖一些包和相应的简单配置就可以,适合新手;

(4)adb shell:利用命令行来调试,推荐这个进阶(大神估计都是直接命令行工作的哈哈哈);