Android Handler 内存泄漏

三味码屋 2023年09月08日 695次浏览

非静态内部类隐式持有对外部类对象的引用

示例代码:

public class Outer {

    int outerField = 0;

    /**
     * 非静态内部类
     */
    class Inner {

        void innerMethod() {
            System.out.println("outerField: " + outerField);
        }
    }
}

调用内部类中的方法,断点调试:
非静态内部类持有外部类对象 this$0
可以看到,内部类中持有外部类的一个对象 this$0

Handler 内存泄露

原因

Handler 匿名内部类或者非静态内部类持有对外部类对象的强引用,外部类对象销毁后占据的内存无法释放。

引用链

ActivityThread -> Looper -> MessageQueue -> Message -> Handler -> 外部类(例如:Activity、Service等)。

解决方法

原理

阻断引用链

具体方法
  1. Handler 改为静态内部类,静态内部类不会隐式持有对外部类对象的引用,阻断 Handler -> 外部类 引用环节。
  2. Handler 持有对外部类弱引用对象的引用,将 Handler -> 外部类 这一环节变为弱引用,弱引用在 JVM 执行 GC 时会被回收。
  3. 当外部类对向销毁时,清除消息队列中的所有消息,消息在被清除时,会释放
    Message -> Handler 引用。

参考

从源码角度看Handler为何会发生内存泄露
深入理解Java中为什么内部类可以访问外部类的成员
Java内存泄漏系列--匿名内部类导致内存泄露--原因/解决方案
强引用 弱引用 软引用 虚引用 的区别以及使用场景