前言
面试中最常问的就是:“你了解Android内存泄漏和Android内存溢出的原因吗,请简述一下” ,然后大多数的人都能说出原因及其例子和解决办法,但是实际项目中稍微不注意还是会导致内存泄漏,今天就来梳理一下那些是常见的内存泄漏写法和解决方法。
原因
内存泄漏的原理很多人都明白,但是为了加强大家的防止内存泄漏的意识,我再来说一遍。说到内存泄漏的原理就必须要讲一下Java的GC的。Java之所以这么流行不仅仅是他面向对象编程的方式,还有一个重要的原因是因为,它能帮程序员免去释放内存的工作,但Java并没有我们想象的那么智能,它进行内存清理还得依靠固定的判断逻辑。
Java的GC可分为
引用计数算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;在任何时刻计数器的值为0的对象就是不可能再被使用的,也就是可被回收的对象。这个原理容易理解并且效率很高,但是有一个致命的缺陷就是无法解决对象之间互相循环引用的问题。如下图所示
可达性分析算法
针对引用计数算法的致命问题,可达性分析算法能够轻松的解决这个问题。可达性算法是通过从GC root往外遍历,如果从root节点无法遍历该节点表明该节点对应的对象处于可回收状态,如下图中obj1、obj2、obj3、obj5都是可以从root节点出发所能到达的节点。反观obj4、obj6、obj7却无法从root到达,即使obj6、obj7互相循环引用但是还是属于可回收的对象最后被jvm清理。
看了这些知识点,我们再来寻找内存泄漏的原因,Android是基于Java的一门语言,其垃圾回收机制也是基于Jvm建立的,所以说Android的GC也是通过可达性分析算法来判定的。但是如果一个存活时间长的对象持有另一个存活时间短的对象就会导致存活时间短的对象在GC时被认定可达而不能被及时回收也就是我们常说的内存泄漏。Android对每个App内存的使用有着严格的限制,大量的内存泄漏就可能导致OOM,也就是在new对象请求空间时,堆中没有剩余的内存分配所导致的。
既然知道了原理那么平时什么会出现这种问题和怎么合理的解决这种问题呢。下面来按实例说话。
内存泄漏的例子
Handler
说到Handler这个东西,大家平时肯定没少用这玩意,但是要是用的不好就非常容易出现问题。举个例子
public Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
toast("handle