Android Handler内存泄露和不会ANR原因↑

Android应用中,不当使用Handler可能导致内存泄露,因为Handler与主线程Looper关联,Message队列中Message会保持对Handler及外部Activity的引用。内存泄露主要由非静态内部类的隐式引用引起。解决方案包括使用静态内部类和WeakReference,或者静态Runnable。Looper.loop()的死循环不会导致ANR,因在无消息时会通过epoll机制进入等待状态,且主线程的生命周期与Looper.loop()密切相关,只有处理Message时才可能触发ANR。
摘要由CSDN通过智能技术生成

1.handler容易引发内存泄露

面试时经常被问到的一个问题:如何避免Handler造成内存泄漏?

内存泄漏:当不再需要某个实例后,这个对象却仍然被引用,不能被垃圾回收,这个情况就叫做内存泄露。

Handler使用不当很容易引起内存泄露,比如:

public class MainActivity extends Activity {

  private final Handler mHandler = new Handler() {

    @Override

      public void handleMessage(Message msg) {

            // ... 

      }

   }

}

这样使用handler的时候,其实是将handler定义为了匿名内部类。造成这段代码可能导致内存泄露。Android Lint会提示以下信息:

In Android, Handler classes should be static or leaks might occur.

 

那Handler引发内存泄露的原因是什么呢?

①当一个Android应用程序启动的时候,Android框架为这个程序的主线程创建了一个Looper对象,用于处理Handler发送过来的Message。Looper会创建对应的消息队列messagequeue,然后不断循环的处理其中的message。所有的应用程序框架的事件(比如Activity生命周期的调用、按钮的点击等)都被封装在这个Message对象里,然后被加入到Looper对应的Messagequeue中,最后一个一个的被处理。注意,主线程的Looper在整个应用程序的生命周期中一直存在

②在主线程中实例化一个Handler对象的时候,就和它关联了主线程Looper的消息队列。消息被发送到消息队列时,入队列之前会把handler赋值给message的target属性,这样Message就持有了这个Handler对象的引用。(也就是说,只要没有处理到这个Message,Handler就一直在队列中被引用)

在Java中,非静态内部类和匿名内部类都隐式的保持了对外部类的引用。但是静态内部类不会有这个引用

Message持有Handler的引用;Handler是内部类,它持有外部类Activity的引用;只要这个Message不被处理,那外部类Activity就永远不会被释放,哪怕是它已经不再被需要时调用了它的onDestroy方法,也无法释放,这样就引发了内存泄漏

0df858c41c6a0b2e729b24ff3aa57bcd.jpeg

探究Handler导致内存泄露的真正原因:

handler发送消息后,消息会进行入队操作,在enqueueMessage方法中:

msg.targer = this;

this指的就是handler,所以handler被message持有了,而message放入消息队列后,message又被MessageQueue持有了,而MessageQueue是在创建Looper的时候生成的:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值