内存泄漏之弱引用的Handler为什么不会被回收掉?

目录

前言:

Handler的基本使用

为什么要使用弱引用?

为什么软引用的Handler不会被收回?

如何证明Handler和一个GCRoot之间有强引用呢?


前言:

文章,一为温故而知新,二若是可以帮助到别人,也是我的荣幸。

因本人能力有限,若有错误之处,麻烦指出。如果觉得有可取之处,麻烦点赞支持一下。 😊

Handler的基本使用

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;
    private final MyHandler mHandler = new MyHandler(new WeakReference<MainActivity>(this));

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.textView);
        mHandler.sendEmptyMessage(1);

    }

    private static class MyHandler extends Handler {

        private final WeakReference<MainActivity> mReference;

        public MyHandler(WeakReference<MainActivity> reference) {
            super();
            mReference = reference;
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            MainActivity activity = mReference.get();
            if (activity != null) {
                TextView textView = activity.mTextView;
                textView.setText("just a test");
            }
        }
    }
}

MyHandler继承Handler,并使用静态内部类,从而不持有外部类的引用,若需要在handler中使用Activity中的成员变量,则需要通过Activity的弱引用拿到成员变量。

为什么要使用弱引用?

若直接传入Activity的引用,则会使MyHandler持有Activity的引用,从而导致静态内部类失效。

为什么软引用的Handler不会被收回?

在才接触弱引用的时候,就一直很好奇,弱引用不是gc的时候就会被回收么?那么Activity和Handler之间是弱引用,岂不是只要发生gc,handler就会被收回么? 这样的话,里面的runnable应该就都处理不了,为什么网上都还建议使用弱引用?是网上的东西都错了么?

这个问题困扰的了我很久,也询问过很多人,都没有得到一个很好的答案。于是,我开始看虚拟机是如何进行内存收回的。

Java虚拟机使用的是可达性分析算法进行内存回收。可达性分析算法解释

Handler不会被回收的话,肯定是和一个gcroot之间有强引用。

猜测图型:

如何证明Handler和一个GCRoot之间有强引用呢?

上图是一张通过profile抓取的memory的截图。官方文档对Depth进行了这样的解释,从任意GC根到选定实例的最短跳数。那么depth = 0,就代表着它为GCRoot,也就是说mlooper,mQueue都是GCRoot,而Handler又持有它们的引用,所以Handler不光是和GCRoot之间有强引用连接,而且还是多个GCRoot。

那么有那些GCRoot呢?

Java语言中,可以作为GCRoots的对象有下面四种(来自深入理解Java虚拟机第三章64页):

  • 虚拟机栈中引用的对象
  • 方法区中的类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

上图中的handler使用的是主线程中的Looper,于是对应的Looper是sMainLooper是一个静态变量,匹配上面的第二个。 但是这个类静态属性让我有点慌,持怀疑态度。

而mQueue对应着方法区中常量引用的对象。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值