记一次ViewPager + RecyclerView的内存泄漏

RecyclerView内存泄漏分析与解决

基本情况

之前在项目上做内存泄漏优化的时候有一个关于RecyclerView内存泄漏,页面结构如图:

pic_layer.png

LeakCanary捕获的引用链如下

┬───
│ GC Root: Thread object
│
├─ java.lang.Thread instance
│    Thread name: 'main'
│    ↓ Thread.threadLocals
│             ~~~~~~~~~~~~
├─ java.lang.ThreadLocal$ThreadLocalMap instance
│    ↓ ThreadLocal$ThreadLocalMap.table
│                                 ~~~~~
├─ java.lang.ThreadLocal$ThreadLocalMap$Entry[] array
│    ↓ ThreadLocal$ThreadLocalMap$Entry[4]
│                                      ~~~
├─ java.lang.ThreadLocal$ThreadLocalMap$Entry instance
│    ↓ ThreadLocal$ThreadLocalMap$Entry.value
│                                       ~~~~~
├─ androidx.recyclerview.widget.GapWorker instance
│    ↓ GapWorker.mRecyclerViews
│                ~~~~~~~~~~~~~~
├─ java.util.ArrayList instance
│    ↓ ArrayList[0]
│               ~~~
╰→ androidx.recyclerview.widget.RecyclerView instance

找出问题

从引用链可以看出关键点在于GapWorker,首先看看这个GapWorker

RecyclerView在android 21及以上版本会使用GapWorker实现预加载机制,在Recyclerview的onAttachedToWindow方法中尝试将其实例化,并通过GapWorker的add方法将Recyclerview自身添加到GapWoker的成员变量mRecyclerViews链表中去,在onDetachedFromWindow会调用GapWorkerremove方法移除其对自身的引用,GapWoker实例保存在其类静态成员变量sGapWorker(ThreadLocal)中,确保主线程只有一个实例

 RecyclerView
 
 @Override
    protected void onAttachedToWindow() {
   
   
        ......
        if (ALLOW_THREAD_GAP_WORK) {
   
   
          //从ThreadLocal中获取GapWorker实例,为null则直接创建一个
            mGapWorker = GapWorker.sGapWorker.get();
            if (mGapWorker == null) {
   
   
                mGapWorker = new GapWorker();
                Display display = ViewCompat.getDisplay(this);
                float refreshRate = 60.0f;
                if (!isInEditMode() && display != null) {
   
   
                    float displayRefreshRate = display.getRefreshRate();
                    if (displayRefreshRate >= 30.0f) {
   
   
                        refreshRate = displayRefreshRate;
                    }
                }
                mGapWorker.mFrameIntervalNs = (long) (1000000000 / refreshRate);
              //将创建的GapWorker实例设置到ThreadLocal中去
                GapWorker.sGapWorker.set(mGapWorker);
            }
          //添加自身的引用
            mGapWorker.add(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值