Android中使用Handler造成内存泄露的原因和解决方法

1.参考文献

http://www.linuxidc.com/Linux/2013-12/94065.htm

2.什么是内存泄露(Memory Leak)

内存泄露是指程序向系统申请内存后,无法释放已申请的内存的内存空间。造成的结果是程序本身无法再访问申请的那块内存,系统也不能将它分配给其他程序。一次内存泄露的危害可以忽略,但多次内存泄露堆积之后,会导致内存使用过高,导致OOM(内存溢出)。

3.Java中的内存回收机制

Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可达状态,则将该对象从内存中回收。所谓的不可达状态是指一个对象不被任何引用所指向。另外如果一组对象中只包含相互的引用,而没有来自它们外部的引用(如有AB两个对象互相持有引用,但没有任何外部对象持有指向A或B的引用),这也属于不可达状态。

4.Android中使用Handler造成内存泄露的原因

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bitmap bitmap = (Bitmap) msg.obj;
            mImageView.setImageBitmap(bitmap);
        }
    };

上面是Handler的一个简单使用,当使用内部类来创建Handler的时候,Handler对象会隐式地持有一个外部类对象的引用(否则怎么可能通过Handler操作Activity中的View)。而Handler通常会伴随着一个耗时的后台线程(如从网络加载图片)一起出现,

new Thread(){
            @Override
            public void run() {
                //.....
                Message msg = new Message();
                mHandler.sendMessage(msg);
            }
        }.start();

在后台线程执行完毕后,通过消息机制通知Handler,然后Handler把图片更新到界面。

如果用户在网络请求过程中关闭Activity,正常情况下,该Activity不在被使用,就有可能在GC检查时被回收掉但由于这时线程尚未执行完毕,该线程持有Handler的引用,Handler又吃用Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束。

另外如果执行Handler的postDelayed()方法,该方法会将Handler装入到Message中,并把Message加入到MessageQueue中那么在设定delay到达之情,会有一条MessageQueue->Message->Handler->Activity的引用链,也会导致Activity被持有引用而无法回收。

5.使用Handler导致内存泄露的解决方法

 1)在关闭Activity的时候停止后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity也就会被回收了。如果Handler是被delay的Message持有了引用,则执行Handler的removeCallbacks()方法,将消息对象从消息队列中移除就可以了。

 2)将Handler声明为静态类

静态类不持有外部类的对象,所以Activity可以被随意回收。但是由于Handler不再持有外部类对象的引用,导致无法在Handler中操作Activity中的对象了。所以需要在Handler中增加一个对Activity的弱引用(WeakReferece):

private static class MyHandler extends Handler {
    WeakReference<Activity > mActivityReference;

    MyHandler(Activity activity) {
        mActivityReference= new WeakReference<Activity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        final Activity activity = mActivityReference.get();
        if (activity != null) {
            mImageView.setImageBitmap(mBitmap);
        }
    }
}

6.什么是WeakReference?

WeakReference弱引用,与强引用(即我们常说的引用)相对,它的特点是,GC在回收时会忽略掉弱引用,即就算有弱引用指向某对象,但只要该对象没有被强引用指向(实际上多数时候还要求没有软引用,但此处软引用的概念可以忽略),该对象就会在被GC检查到时回收掉。对于上面的代码,用户在关闭Activity之后,就算后台线程还没结束,但由于仅有一条来自Handler的弱引用指向Activity,所以GC仍然会在检查的时候把Activity回收掉。这样,内存泄露的问题就不会出现了。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值