美文网首页
LeakCanary浅析

LeakCanary浅析

作者: Jesse_zhao | 来源:发表于2018-05-28 21:39 被阅读41次

    一、使用

    public class ExampleApplication extends Application {
     public static RefWatcher getRefWatcher(Context context) {
    ExampleApplication application = (ExampleApplication) context.getApplicationContext();
    return application.refWatcher;
    }
    private RefWatcher refWatcher;
    @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
     //监测当前应用内存泄露的是进程是否正在运行,
     //如果正在运行则不用再次进行初始化,否则进行初始化操作。
      return;
    }
    refWatcher =LeakCanary.install(this);
    // Normal app init code...
        }
    }
    

    LeakCanary的使用非常的简单,两行代码搞定。当然也可以主动的添加需要监听的对象;
    LeakCanary.install(this);调用之后会返回一个RefWatcher对象,然后就可以调用观察分析某个对象:

    public abstract class BaseFragment extends Fragment {
    @Override public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
    refWatcher.watch(this);
     }
    }
    

    我们就从这上面那两行代码开始进行分析。

    二、LeakCanary.isInAnalyzerProcess(this)

    public static boolean isInAnalyzerProcess(Context context) {
    return isInServiceProcess(context, HeapAnalyzerService.class);
    }
    

    ->LeakCanary.isInServiceProcess()

     public static boolean isInServiceProcess(Context context, Class<? extends Service> serviceClass) {
    PackageManager packageManager = context.getPackageManager();
    PackageInfo packageInfo;
    try {
      //获取当前应用注册的Service信息
      packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES);
    } catch (Exception e) {
      CanaryLog.d(e, "Could not get package info for %s", context.getPackageName());
      return false;
    }
    String mainProcess = packageInfo.applicationInfo.processName;
    
    ComponentName component = new ComponentName(context, serviceClass);
    ServiceInfo serviceInfo;
    try {
      //查找HeapAnalyzerService信息
      serviceInfo = packageManager.getServiceInfo(component, 0);
    } catch (PackageManager.NameNotFoundException ignored) {
      // 找不到HeapAnalyzerService相应信息 返回false
      return false;
    }
    //判断HeapAnalyzerService所在的进程名称是否和宿主进程一样
    if (serviceInfo.processName.equals(mainProcess)) {
      return false;
    }
    //判断HeapAnalyzerService是否正在运行
    int myPid = android.os.Process.myPid();
    ActivityManager activityManager =
        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.RunningAppProcessInfo myProcess = null;
    List<ActivityManager.RunningAppProcessInfo> runningProcesses =
        activityManager.getRunningAppProcesses();
    if (runningProcesses != null) {
      for (ActivityManager.RunningAppProcessInfo process : runningProcesses) {
        if (process.pid == myPid) {
          myProcess = process;
          break;
        }
      }
    }
    if (myProcess == null) {
      CanaryLog.d("Could not find running process for %d", myPid);
      return false;
    }
    
    return myProcess.processName.equals(serviceInfo.processName);
    }
    

    这段代码相对比较简单主要是判断HeapAnalyzerService是否已经启动了,如果启动了就不用再进行初始化启动了。

    三、LeakCanary.install(this)

    初始化并且开始监听每个Activity销毁时是否存在内存泄露。

      public static RefWatcher install(Application application) {
    return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        .buildAndInstall();
     }
    
    3.1、LeakCanary.refWatcher()
      public static AndroidRefWatcherBuilder refWatcher(Context context) {
    return new AndroidRefWatcherBuilder(context);
    

    }

    3.2、AndroidRefWatcherBuilder.listenerServiceClass()

    添加监听

    public AndroidRefWatcherBuilder listenerServiceClass(
      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
    }
    

    创建内存回收监听器
    -> ServiceHeapDumpListener()

    public ServiceHeapDumpListener(Context context,
      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
      //向PageManage注册DisplayLeakService和HeapAnalyzerService
    setEnabled(context, listenerServiceClass, true);
    setEnabled(context, HeapAnalyzerService.class, true);
    this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");
    this.context = checkNotNull(context, "context").getApplicationContext();
    }
    
    3.3、AndroidRefWatcherBuilder.buildAndInstall()
      public RefWatcher buildAndInstall() {
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
        //向PageManage注册DisplayLeakActivity
      LeakCanary.enableDisplayLeakActivity(context);
      //监听activity销毁事件
      ActivityRefWatcher.install((Application) context, refWatcher);
    }
    return refWatcher;
    

    }

    3.4、 ActivityRefWatcher.install()
    public static void install(Application application, RefWatcher refWatcher) {
    new ActivityRefWatcher(application, refWatcher).watchActivities();
    }
    

    注册Activity销毁事件监听
    -> ActivityRefWatcher.watchActivities()

     public void watchActivities() {
    // Make sure you don't get installed twice.
    stopWatchingActivities();
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
    }
      private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new Application.ActivityLifecycleCallbacks() {
        @Override public void onActivityDestroyed(Activity activity) {
          //在Activity销毁会会调用这个方法
      ActivityRefWatcher.this.onActivityDestroyed(activity);
        }
      };
    }
    

    在Activity销毁时,对销毁的Activity的进行追踪和分析。

    3.5、RefWatcher.ensureGoneAsync()
      private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
    watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });
    }
    

    使用线程池进行异步分析:

        Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    //移除已经被回收的activity实例对应的KeyedWeakReference(见3.5.1)
    removeWeaklyReachableReferences();
    
    if (debuggerControl.isDebuggerAttached()) {
      // The debugger can create false leaks.
      return RETRY;
    }
    //判断当前activity是否被回收了
    if (gone(reference)) {
      return DONE;
    }
    //发起gc
    gcTrigger.runGc();
     //移除已经被回收的activity实例对应的KeyedWeakReference(见3.5.1)
    removeWeaklyReachableReferences();
    //当 retainedKeys中还存在当前activity实例对应的KeyedWeakReference时,
    //说明当前Activity已经发生内存泄漏了
    if (!gone(reference)) {
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
    
      File heapDumpFile = heapDumper.dumpHeap();
      if (heapDumpFile == RETRY_LATER) {
        // Could not dump the heap.
        return RETRY;
      }
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
     //分析activity堆信息
      heapdumpListener.analyze(
          new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
              gcDurationMs, heapDumpDurationMs));
    }
    return DONE;
    }
    
    3.5.1、RefWatcher.removeWeaklyReachableReferences()
    private void removeWeaklyReachableReferences() {
    KeyedWeakReference ref;
    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
      retainedKeys.remove(ref.key);
    }
    }
    

    这个主要判断当前Activity是否存在内存泄露。原理就是:
    通过创建WeakRrefences对象,它包含一个queue,当jvm开始gc时,如果WeakRrefences包含的对象被回收,则会加入到这个queue中。那么通过这个queue就可以知道当前的这个实例是否被回收了还是没有被回收。

    四、总结

    原理也比较简单在触发GC时
    利用了WeakRrefences和WeakRrefencesQueue判断某个对象是否已经被回收。

    相关文章

      网友评论

          本文标题:LeakCanary浅析

          本文链接:https://www.haomeiwen.com/subject/omenjftx.html