Android性能优化-内存泄漏1

来源:互联网 发布:foreach循环遍历数组 编辑:程序博客网 时间:2024/06/05 18:48
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。即所谓内存泄漏。
(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
-----------------------------------------------------------------以上摘自百度百科--------------------------------------------------------------


那么我们现在来谈一下在Android开发过程中会出现的内存泄漏问题
Android应用程序本身系统分配的内存很少,一旦发生泄漏,程序很快就会变得非常卡顿,直至OOM崩溃


场景1:静态变量导致的内存泄漏

下面的情况相当简单,但是在最初的开发过程中,我也是犯过这样的错误的,上代码:



这样的代码会导致activity 无法正常的被销毁,原因是静态变量mContext 引用了它。

场景2:单例模式导致的内存泄漏
单例模式具有静态特性,使得单例的生命周期和应用的生命周期一样长, 如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。
话不多少 上代码:


这是一个简单的单例模式;
在activity 中的调用 是这样的:


那么当退出这个Activity ,需要 GC回收的时候,他就会发现Activity 回收失败,因为单例中持有它得引用。
那么遇到这样的问题,我们要如何处理呢?现在笔者想到了两种办法:
方法一:
            使单例模式中持有的引用 是一个可以和应用生命周期一样长的引用;
上代码:

这样子修改,不管外面传入什么Context,最终都会使用Applicaton的Context,而我们单例的生命周期和应用的一样长,这样就防止了内存泄漏。
方法二:
            使用弱引用处理单例模式:
上代码:



如果有困惑,请看下面的解释:这里只简单的分析一下弱引用:
A a = new A();
B b = new B(a);
B的默认构造函数上是需要一个A的实例作为参数的,那么这个时候 A和B就产生了依赖
如果这时候我们将a = null(将a置空);当一个对象不再被其他对象引用的时候,是会被GC回收的,很显然及时a=null,那么A对象也是不可能被回收的,因为B依然依赖与A,在这个时候,造成了内存泄漏!

如何避免上面的例子中内存泄漏呢?

A a = new A();

B b = new B(a);

a = null;

b = null;

这个时候B对象再也没有被任何引用,A对象只被B对象引用,尽管这样,GC也是可以同时回收他们俩的。

另外:

A a = new A();

WeakReference wr = new WeakReference(a);

当 a=null ,这个时候A只被弱引用依赖,那么GC会立刻回收A这个对象,这就是弱引用的好处!他可以在你对对象结构和拓扑不是很清晰的情况下,帮助你合理的释放对象,造成不必要的内存泄漏!!
场景3:属性动画导致的内存泄漏

例如下面的代码,由于该属性动画为循环动画,如果在Activity销毁时,没有取消动画,那么虽然我们看不见动画在执行,实际上动画仍然一直播放下去,这个时候Button会被动画所持有,而Button又持有对应的Activity对象,那么就会造成Activity无法正常释放。



在Activity 的onDestory()方法中 要调用cancle()方法,即可释放资源。

场景4:查询数据库未关闭游标
场景5:Adapter没有复写convertview
场景6:Bitmap对象不再使用时未调用recycle()释放内存


以上场景属于下问题可以及时避免;就不一一赘述。
下篇将进行进一步讲解:线程及内存泄漏之间的关系。

2 0
原创粉丝点击