leakcanary

这篇文章中介绍了内存泄露检测的原理:Reference、ReferenceQueue

这篇文章有分析流程

三个核心知识点

1、Reference与ReferenceQueue
@Test
    public void testQueue()
    {
        A a=new A();
        ReferenceQueue queue=new ReferenceQueue();
        WeakReference reference=new WeakReference(a,queue);

        a=null;
        Runtime.getRuntime().gc();
        System.runFinalization();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Reference poll=null;
        while ((poll=queue.poll())!=null)
        {
            System.out.println(poll.toString());
        }
    }

输出结果:


queue中有数据

修改代码:

//a=null;

测试结果:


queue中无数据

结论:

如果一个对象只是弱可达的(就是说没有强引用指向它,只有弱引用指向它,那么在gc时这个对象就是可回收的),那么在gc时,这个对象就会被回收,并且会将这个对象的弱引用放到queue中

leakcanary核心原理

以Activity为例,在Activity的onDestroy生命周期方法中,首先为这个Activity生成一个唯一的uuid,然后将这个uuid添加到一个set集合中,然后为这个Activity新建一个含有queue的WeakReference,那么如果说发生gc时,这个Activity被回收了,那么这个queue中就有数据,如果没有被回收,那么这个queue中就没有数据,这个Activity可能就发生了内存泄露;
下一步就是判断有没有发生内存泄露,具体做法是遍历这个queue然后根据对应关系移除set中的元素

while ((ref = (KeyedWeakReference) queue.poll()) != null) {
      retainedKeys.remove(ref.key);
    }

遍历完成之后,set中存在的元素就是可能发生内存泄露的对象,为了判断的准确性;第三部再次调用gc;第四步再次重复上面的循环;最后如果说这个set集合中还存在这个reference的可以那么就可以确定这个对象发生了内存泄露

2、如何统一监测Activity、Fragment、普通对象的生命周期

Activity

application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
 private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new ActivityLifecycleCallbacksAdapter() {
        @Override public void onActivityDestroyed(Activity activity) {
          refWatcher.watch(activity);
        }
      };

Fragment

 application.registerActivityLifecycleCallbacks(helper.activityLifecycleCallbacks);
private final Application.ActivityLifecycleCallbacks activityLifecycleCallbacks =
        new ActivityLifecycleCallbacksAdapter() {
          @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            for (FragmentRefWatcher watcher : fragmentRefWatchers) {
              watcher.watchFragments(activity);
            }
          }
        };
private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
      new FragmentManager.FragmentLifecycleCallbacks() {

        @Override public void onFragmentViewDestroyed(FragmentManager fm, Fragment fragment) {
          View view = fragment.getView();
          if (view != null) {
            refWatcher.watch(view);
          }
        }

        @Override
        public void onFragmentDestroyed(FragmentManager fm, Fragment fragment) {
          refWatcher.watch(fragment);
        }
      };

  @Override public void watchFragments(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
  }

图片地址:https://juejin.im/post/5c72af2af265da2de165a624

image.png
根据源码leakcanary只能 检测Activity、Fragment的泄露情况,无法检测其他的对象
3、Runtime.getRuntime().gc()与System.gc()

区别

    public static void gc() {
        boolean shouldRunGC;
        synchronized (LOCK) {
            shouldRunGC = justRanFinalization;
            if (shouldRunGC) {
                justRanFinalization = false;
            } else {
                runGC = true;
            }
        }
        if (shouldRunGC) {
            Runtime.getRuntime().gc();
        }
    }

justRanFinalization这个值是调用runFinalization方法来设置的

 public static void runFinalization() {
        boolean shouldRunGC;
        synchronized (LOCK) {
            shouldRunGC = runGC;
            runGC = false;
        }
        if (shouldRunGC) {
            Runtime.getRuntime().gc();
        }
        Runtime.getRuntime().runFinalization();
        synchronized (LOCK) {
            justRanFinalization = true;
        }
    }

所以单纯调用System.gc()是不会触发Runtime.getRuntime().gc()的。但是会把这次尝试纪录下来,等到下次调用System.runFinalization()时,会先执行这个Runtime.getRuntime().gc()。

你可能感兴趣的:(leakcanary)