Android内存泄漏总结

内存泄漏问题老生常谈,很常见也很难根治,今天我在这里总结一下内存泄漏的原因和解决方法:

所谓内存泄漏,就是本该被回收的对象,由于某些原因不能被回收,继续占用堆内存的这种状态,导致的结果也是显而易见的,会占用我们本可以使用的内存空间,当超出允许的内存时会引起OOM崩溃。

导致内存泄漏的原因大致分为:

  1. 集合类
  2. static修饰的成员变量
  3. 资源对象使用后未被关闭
  4. 非静态内部类/匿名类

1.集合类引起的内存泄漏:

当一个对象添加至集合中的时候,该对象会被集合引用到,当想要释放的时候不能释放,只有在集合被销毁的时候该对象才可以被释放

1 // 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
2 List<Object> objectList = new ArrayList<>();        
3        for (int i = 0; i < 10; i++) {
4             Object o = new Object();
5             objectList.add(o);
6             o = null;
7         }
8 // 虽释放了集合元素引用的本身:o=null)
9 // 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象

解决方法:

因为是集合把对象引用了,那只需要吧集合释放掉集合对元素的引用也会被释放

//释放集合
objectList .clear(); objectList
= null;

2.static修饰的成员变量:

因为被static修饰的成员变量生命周期 = 应用程序的生命周期,会在类被创建的时候加载到内存

static静态成员变量的生命周期>该类的生命周期导致该类没法释放

public class SecondActivity extends Activity{  
    private Handler mHandler = new Handler(){  
        @Override  
        public void handleMessage(Message msg) {  
            super.handleMessage(msg);  
            SecondActivity.this.finish();  
            this.removeMessages(0);  
        }  
    };  
  
    private static Haha haha;  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        haha = new Haha();  
        mHandler.sendEmptyMessageDelayed(0,2000);  
    }  
  
    class Haha{  
  
    }  
}  

像上面这种情况SecondActivity是无法被释放掉的,只有把该静态成员变量置为null,这时就不会导致内存泄漏

protected void onDestroy() {  
    super.onDestroy();  
    if(haha!=null){  
        haha = null;  
    }  
}  

更常见的问题是在我们使用单例模式的时候:

public class LeakSingleInstance {

    private static LeakSingleInstance mInstance;
    private Context mContext;
    
    private LeakSingleInstance(Context mContext){
        this.mContext = mContext;
    }
    public static LeakSingleInstance getInstance(Context mContext) {
        if(mInstance == null) {
            mInstance = new LeakSingleInstance(mContext);
        }
        return mInstance;
    }
}

这个在创建的时候AndroidStudio就提示有内存泄漏了,原因显而易见的,我们的单例模式的类是长期存在的,生命周期 = 应用生命周期,我们如果传入了上下文会导致该上下文长期被持有,不被释放,导致内存泄漏

解决方法可以使用:

mContext.getApplicationContext()

直接获取ApplicationContext的上下文使用,但是ApplicationContext使用是有局限性的,使用的时候要注意。

3.资源对象使用后未被关闭

对于资源的使用(如 广播BraodcastReceiver、文件流File、数据库游标Cursor、图片资源Bitmap等),若在Activity销毁时无及时关闭 / 注销这些资源,则这些资源将不会被回收,从而造成内存泄漏

// 对于 广播BraodcastReceiver:注销注册
unregisterReceiver()

// 对于 文件流File:关闭流
InputStream / OutputStream.close()

// 对于 数据库游标cursor:使用后关闭游标
cursor.close()

// 对于 图片资源Bitmap:Android分配给图片的内存只有8M,若1个Bitmap对象占内存较多,当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存;最后再赋为null 
Bitmap.recycle();
Bitmap = null;

// 对于动画(属性动画)
// 将动画设置成无限循环播放repeatCount = “infinite”后
// 在Activity退出时记得停止动画

还有非静态内部类和匿名类引起的泄漏,留在下篇再分析

 by:Jungle张轶

posted @ 2018-04-27 10:52  WidgetBox  阅读(217)  评论(0编辑  收藏  举报