Handler内存泄漏的原因是什么?为什么其他内部类没有这个问题?

本文深入解析Handler机制导致的内存泄漏问题,阐述了内部类持有外部类引用的原理,以及MessageQueue、Message和Handler之间的关系如何引起泄漏。并对比了ViewHolder等其他内部类为何不会引发相同问题,最后提供了软引用和static等解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Handler为什么会内存泄漏?

内部类持有了外部类的引用。

    Handler handler = new Handler() {
	
        @Override
        public void handleMessage(Message msg) {
            MainActivity.this.click();
            //click();
        }
    };
	
    public void click(){
    	...
    }

就像上面的代码,Handler的内部类中的handleMessage中可以调用外面的click()方法,至于为什么可以调用呢?click()方法的写法上来说是省略了前面的 MainActivity.this. ,然后虚拟机给默认添加了,这就说明,在这个内部类里面,它默认的持有了这个变量,也恰恰是因为它持有了这个变量,它才能可以调用外面的方法。

假如说MainActivity执行了onDestory()方法,这个MainActivity会被释放吗?并不会,因为Java虚拟机中有一个可达性分析,Java 虚拟机就认为,这个MainActivity由于被Handler使用,所以它不能被释放,这个Activity被内部类持有后,只要内部类不被释放,他就不能被释放。

 

为什么其他内部类没有这个问题?

在RecycleView中,也有一个内部类叫做ViewHolder,它并没有内存泄漏,而偏偏Handler有内存泄漏呢?

有没有记得Handler中有一个方法叫做 sendMessageDelayed()。这个Delayed方法可以是2秒后执行,可以是1分钟之后执行,

因为我们的消息被放在了消息队列里面,如果这个消息要在1分钟之后才能执行,那么这个消息会一直被MessageQueue持有着,这个消息就被一直放在这个队列里面。

这个消息一直放在队列里会带来什么样的影响?

还有handler.sendMessage  -> messageQueue.enqueueMessage -> messageQueue添加消息,再到 Looper -> loop() -> messageQueue -> next -> dispatchMessage -> handler.handleMessage 处理消息,它是如何做到是同一个handle对象的?

来看到Looper处理消息的时候会干些什么事情,源码在Looper.loop()里面。

他先从MessageQueue中取出一个消息。

Message msg = queue.next(); // might block

然后又执行了dispatchMessage。

msg.target.dispatchMessage(msg);

注意到没有,他这里是根据target来调用的方法,我们再来看看这个target是什么?(Message.java)

    /*package*/ Handler target;

target其实就是一个handler,那target在哪里赋值的?我们回到Handle.java来看调用时候。

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在enqueueMessage之前,把this赋值给了target。

这就说明,Message持有了一个Handler,然而,这个Handler又持有了外部类的this。

这就造成,这个Message在还没有处理完成之前,他一直都会处在队列中间,如果这个消息要1分钟之后才能执行,所以至少要等消息处理完之后,才能够销毁这个Message,销毁Message之后才会销毁Handler,销毁Handler之后才会销毁this。所以,这个时候,就是内存泄漏。

总的来说,就是MessageQueue持有了Message,Message持有了Handler,Handler持有了Activity,只是调用了这个Activity的onDestory()并没有用,因为MessageQueue没有释放Message。

回到正题,为什么其他的内部类没有这个问题呢?

所有的内部类都会持有外部类对象,但其他内部类在持有外部类对象的时候没有什么耗时的操作,也没有另外一个东西去持有这个内部类。

 

如何解决Handler内存泄漏的问题(主线程)?

常用的方法有软引用,static等。

软引用:https://blog.youkuaiyun.com/yichen97/article/details/91488300

static :https://blog.youkuaiyun.com/yichen97/article/details/99086896

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值