Android中Context的内存泄漏

转载自:http://www.jianshu.com/p/9429c35b9571

内存泄漏通常是因为存在着某个对象的引用,而实际上这个对象未来已经不打算使用导致的。
让我们先从一个简单的例子开始:

public class LeakActivity extends Activity {

    public static Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        context = this;
    }
}

这是一个非常简单的内存泄漏的例子,这个Activity被public static Context context引用,导致这个Activity无法被回收。

内存泄漏是因为有变量一直持有这个对象的引用

有个这个简单的例子作为基础,让我们接下来讨论一个稍微有点难度的例子:

public class LeakActivity extends Activity {

    static SQLiteOpenHelper sqLiteOpenHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);

        sqLiteOpenHelper = new SQLiteOpenHelper(this, "", null, 33) {
            @Override
            public void onCreate(SQLiteDatabase db) {

            }

            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            }
        };
    }
}

我们要看这段代码会不会导致内存泄漏,关键要看activity的对象传到SQLiteOpenHelper的构造函数里面之后,这个类是怎么处理这个activity对象的。实际上SQLiteOpenHelper内部把activity作为context保存为了这个类的一个字段,所以只要SQLiteOpenHelper的对象存在,就会一直持有这个Context,导致Activity无法被回收。

SQLiteOpenHelper会持有Context的引用,导致Context无法被回收。

但是仅仅把第一个参数由this改为getApplicationContext()是没用的,这段代码依旧会造成内存泄漏,为了解释这个问题,我们再来看一个例子:

public class LeakActivity extends Activity {

    static Runnable runnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);

        runnable = new Runnable() {
            @Override
            public void run() {

            }
        };
    }
}

这段代码会造成内存泄漏,使得这个Activity无法被释放,因为实现了Runnable接口的匿名内部类,持有了外部类对象的引用。为了证明这个理论,我们可以来看一下这个匿名内部类反编译后的结果:

class LeakActivity$2 implements Runnable {
    LeakActivity$2(LeakActivity this$0) {
        this.this$0 = this$0;
    }

    public void run() {
    }
}

在这个匿名内部类的构造函数里面,传进来了外部对象的引用,并且赋值给了自己类内部的字段this$0。

匿名内部类会持有外部类的引用,导致外部类无法被释放

还有一种情况比较相似,但是却不会导致内存泄漏的情况:

public class LeakActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
    }

    static Runnable runnable = new Runnable() {
        @Override
        public void run() {

        }
    };
}

这段代码的匿名类初始化是在这个类被加载的时候,那个时候还不存在这个类的对象,也就不存在外部类的对象被内部类持有的情况。我们来看一下这个时候这个匿名内部类反编译的结果:

final class LeakActivity$2 implements Runnable {
    LeakActivity$2() {
    }

    public void run() {
    }
}

确实像我们预测的那样,并没有持有外部类的引用。

但是如果我们去掉static关键字,这种情况下,匿名内部类会持有外部类的引用

public class LeakActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
    }

   Runnable runnable = new Runnable() {
       @Override
       public void run() {

       }
   };
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值