LeakCanary源码分析

使用

app的build.gradle配置

dependencies {
    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}

Application配置

    @Override
    public void onCreate() {
        super.onCreate();
        LeakCanary.install(this);
    }

分析

从LeakCanary.install(this)入手,先看看install(this)方法

LeakCanary.java

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

该处使用了构造者的设计模式,并采用了Android的的Builder方式构建,主要是初始化一些参数,我们先来看看最后一个buildAndInstall方法

AndroidRefWatcherBuilder.java

  public RefWatcher buildAndInstall() {
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      LeakCanary.enableDisplayLeakActivity(context);
      ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);
    }
    return refWatcher;
  }

该处build()调用了父类RefWatcherBuilder的build方法,初始化默认的参数,但AndroidRefWatcherBuilder实现了这鞋默认参数,我们来看看有哪些

  //dump内存泄漏处的heap信息,写入hprof文件
  @Override protected HeapDumper defaultHeapDumper() {
    LeakDirectoryProvider leakDirectoryProvider = new DefaultLeakDirectoryProvider(context);
    return new AndroidHeapDumper(context, leakDirectoryProvider);
  }
  //判断是否处于调试模式,调试模式中不会进行内存泄漏检测
  @Override protected DebuggerControl defaultDebuggerControl() {
    return new AndroidDebuggerControl();
  }
  //解析完 hprof 文件并通知 DisplayLeakService 弹出提醒
  @Override protected HeapDump.Listener defaultHeapDumpListener() {
    return new ServiceHeapDumpListener(context, DisplayLeakService.class);
  }
  // 排除可以忽略的泄漏路径
  @Override protected ExcludedRefs defaultExcludedRefs() {
    return AndroidExcludedRefs.createAppDefaults().build();
  }
  //线程控制器,在 onDestroy() 之后并且主线程空闲时执行内存泄漏检测
  @Override protected WatchExecutor defaultWatchExecutor() {
    return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS);
  }

然后继续看buildAndInstall方法,判断处为true,看看LeakCanary.enableDisplayLeakActivity(context)方法,看名字,感觉他是显示可见的Activity

LeakCanary.java

  public static void enableDisplayLeakActivity(Context context) {
    setEnabled(context, DisplayLeakActivity.class, true);
  }

  然后会调用LeakCanaryInternals.setEnabled的setEnabled方法,然后又异步的使用线程池的方式调用了setEnabledBlocking方法,
  //这个方法主要设置DisplayLeakActivity是否可见
  public static void setEnabledBlocking(Context appContext, Class<?> componentClass,
      boolean enabled) {
    ComponentName component = new ComponentName(appContext, componentClass);
    PackageManager packageManager = appContext.getPackageManager();
    int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED;
    // Blocks on IPC.
    packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP);
  }

上面的方法主要是来控制DisplayLeakActivity是否显示到桌面上,也就是那个显示到桌面上的小黄色的图标,我们可以来看看他的清单文件

   <activity
        android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
        android:enabled="false"
        android:icon="@drawable/leak_canary_icon"
        android:label="@string/leak_canary_display_activity_label"
        android:taskAffinity="com.squareup.leakcanary"
        android:theme="@style/leak_canary_LeakCanary.Base" >
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
    </activity>

主要看intent-filter里面的action和category,这种方式的设置,就是显示小图标的小技巧,这个小图标的生命是随我们的app的,我们的app被卸载了,这个小图标也会不存在。


然后我们继续看buildAndInstall方法。

ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);

ActivityRefWatcher.java

 public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
    if (SDK_INT < ICE_CREAM_SANDWICH) {
      // If you need to support Android < ICS, override onDestroy() in your base activity.
      return;
    }
    ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
    activityRefWatcher.watchActivities();
  }

  public void watchActivities() {
    // unregisterActivityLifecycleCallbacks 取消ActivityLifecycle的注册
    stopWatchingActivities();
    //注册Activity的生命周期,监听Activity的启动和销毁
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
  }

  private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new Application.ActivityLifecycleCallbacks() {
        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }

        @Override public void onActivityStarted(Activity activity) {
        }

        @Override public void onActivityResumed(Activity activity) {
        }

        @Override public void onActivityPaused(Activity activity) {
        }

        @Override public void onActivityStopped(Activity activity) {
        }

        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }

        @Override public void onActivityDestroyed(Activity activity) {
          ActivityRefWatcher.this.onActivityDestroyed(activity);
        }
      };

这个地方比较简单,就是给Application注册一个监听Activity的启动和销毁,然后再Activity关闭的时候,被onActivityDestroyed监听到,然后调用onActivityDestroyed方法

  void onActivityDestroyed(Activity activity) {
    refWatcher.watch(activity);
  }

然后我们继续看watch方法,将这个Activity带过去观察

RefWatcher.java

  public void watch(Object watchedReference) {
    watch(watchedReference, "");
  }
  public void watch(Object watchedReference, String referenceName) {
    ...
    final long watchStartNanoTime = System.nanoTime();
    //通过uuid生成唯一的一个key
    String key = UUID.randomUUID().toString();
    //放到set集合
    retainedKeys.add(key);
    //弱引用对象,包裹一些参数,这里面有个ReferenceQueue queue对象,主要功能就是KeyedWeakReference如果被回收了,会被添加到这个ReferenceQueue中
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

    ensureGoneAsync(watchStartNanoTime, reference);
  }

继续看ensureGoneAsync方法,

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

这个地方WatchExecutor来执行execute方法,WatchExecutor是我们在上面AndroidRefWatcherBuilder初始化的,他是AndroidWatchExecutor,而且在创建AndroidWatchExecutor对象的时候,传递了一个5秒的一个参数过来,然后我们来看看这个类。

AndroidWatchExecutor

  //initialDelayMillis是build构建的时候传递进来的参数,为5秒
  public AndroidWatchExecutor(long initialDelayMillis) {
    //创建一个活动在主线程的Handler
    mainHandler = new Handler(Looper.getMainLooper());
    //创建一个活动在子线程的Handler
    HandlerThread handlerThread = new HandlerThread(LEAK_CANARY_THREAD_NAME);
    handlerThread.start();
    backgroundHandler = new Handler(handlerThread.getLooper());
    this.initialDelayMillis = initialDelayMillis;
    maxBackoffFactor = Long.MAX_VALUE / initialDelayMillis;
  }
  //执行的方法
  @Override public void execute(Retryable retryable) {
    //这个地方会进行判断,如果当前是在主线程环境下的话,直接调用waitForIdle
    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      waitForIdle(retryable, 0);
    } else {
    //如果当前是在子线程环境下的话,会调用postWaitForIdle方法,
    //然后又通过主线程的Handler,继续切换到主线程,调用waitForIdle方法,
    //从这个地方就可以看出,execute的执行,在调用waitForIdle方法时,必须是在主线程上面运行
      postWaitForIdle(retryable, 0);
    }
  }

  private void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
    mainHandler.post(new Runnable() {
      @Override public void run() {
        waitForIdle(retryable, failedAttempts);
      }
    });
  }
  //这个地方又用到了一个Handler的小技巧addIdleHandler方法,该方法主要是当Handler在空闲的时候执行操作
  void waitForIdle(final Retryable retryable, final int failedAttempts) {
    // This needs to be called from the main thread.
    Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
      @Override public boolean queueIdle() {
        postToBackgroundWithDelay(retryable, failedAttempts);
        return false;
      }
    });
  }
 //计算出延迟执行postWaitForIdle的时间,然后继续检测。
 //大致可理解为,Handler空闲了,我就每隔几秒去循环检测。
 //检测的执行就是调用Retryable.Result的run方法,该方法已经被在RefWatcher的ensureGoneAsync实现了。
  private void postToBackgroundWithDelay(final Retryable retryable, final int failedAttempts) {
    long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
    long delayMillis = initialDelayMillis * exponentialBackoffFactor;
    backgroundHandler.postDelayed(new Runnable() {
      @Override public void run() {
        //执行retryable.run()方法
        Retryable.Result result = retryable.run();
        //如果run执行的结果是RETRY的话,则继续监测,否则,就停止监测
        if (result == RETRY) {
          postWaitForIdle(retryable, failedAttempts + 1);
        }
      }
    }, delayMillis);
  }

然后我们继续回到RefWatcher的ensureGoneAsync方法

 watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });

return返回执行ensureGone方法,然后我们继续看,这个地方得单独领出来一个一个的讲

  Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

    removeWeaklyReachableReferences();

    if (debuggerControl.isDebuggerAttached()) {
      // The debugger can create false leaks.
      return RETRY;
    }

    if (gone(reference)) {
      //直接返回完成,AndroidWatchExecutor循环监测停止
      return DONE;
    }
    //来到这个步骤的
    gcTrigger.runGc();
    removeWeaklyReachableReferences();
    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);
      heapdumpListener.analyze(
          new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
              gcDurationMs, heapDumpDurationMs));
    }
    return DONE;
  }
removeWeaklyReachableReferences();

循环遍历ReferenceQueue队列,然后取出KeyedWeakReference,如果不为空,就从KeyedWeakReference拿到key字段,然后将他从set集合中移除

 private void removeWeaklyReachableReferences() {
    // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
    // reachable. This is before finalization or garbage collection has actually happened.
    KeyedWeakReference ref;
    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
      retainedKeys.remove(ref.key);
    }
  }
gone(reference)

上面已经进行了一次遍历移除操作,然后继续判断这个KeyedWeakReference的key是否还存在在set集合中,如果不存在在set集合中,说明已经被移除了,也就是说在上一次remove操作中,queue.poll()不为null,意味着gc回收了这个引用,还记得ReferenceQueue的作用吗,记录被回收的引用

  private boolean gone(KeyedWeakReference reference) {
    return !retainedKeys.contains(reference.key);
  }
gcTrigger.runGc()

为了再次验证,手动进行一次gc操作

 @Override public void runGc() {
    Runtime.getRuntime().gc();
    enqueueReferences();
    System.runFinalization();
 }
removeWeaklyReachableReferences();

再一次遍历ReferenceQueue队列

if (!gone(reference))

再一次判断refrence实例是否被回收了,如果还没被回收,就进行分析泄漏原因。

File heapDumpFile = heapDumper.dumpHeap();

来看下heapDumper.dumpHeap(),heapDumper对象是在build的时候初始化的,他是AndroidHeapDumper类

AndroidHeapDumper

@Override 
public File dumpHeap() {
//创建hprof文件,具体可以看DefaultLeakDirectoryProvider的newHeapDumpFile方法
    File heapDumpFile = leakDirectoryProvider.newHeapDumpFile();

    if (heapDumpFile == RETRY_LATER) {
      return RETRY_LATER;
    }

    FutureResult<Toast> waitingForToast = new FutureResult<>();
    showToast(waitingForToast);

    if (!waitingForToast.wait(5, SECONDS)) {
      CanaryLog.d("Did not dump heap, too much time waiting for Toast.");
      return RETRY_LATER;
    }

    Toast toast = waitingForToast.get();
    try {
      Debug.dumpHprofData(heapDumpFile.getAbsolutePath());
      cancelToast(toast);
      return heapDumpFile;
    } catch (Exception e) {
      CanaryLog.d(e, "Could not dump heap");
      // Abort heap dump
      return RETRY_LATER;
    }
  }

该端代码主要功能就是创建一个hprof文件,然后调用 Debug.dumpHprofData() 方法 dump 当前堆内存并写入刚才创建的文件。然后继续看上面ensureGone方法

heapdumpListener.analyze
 heapdumpListener.analyze(
          new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
              gcDurationMs, heapDumpDurationMs));

new HeapDump比较简单,就是一个包装类,将这个参数保存放到这个HeapDump类里面。

heapdumpListener是在build的时候初始化的ServiceHeapDumpListener类,具体可以看AndroidRefWatcherBuilder类中的defaultHeapDumpListener方法,该方法带了两个参数:context和DisplayLeakService.class

然后我们来看ServiceHeapDumpListener类的analyze方法

 public ServiceHeapDumpListener(Context context,
      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    setEnabled(context, listenerServiceClass, true);
    setEnabled(context, HeapAnalyzerService.class, true);
    this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");
    this.context = checkNotNull(context, "context").getApplicationContext();
  }

  @Override public void analyze(HeapDump heapDump) {
    checkNotNull(heapDump, "heapDump");
    HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
  }

listenerServiceClass就是 DisplayLeakService,然后我们继续看 HeapAnalyzerService.runAnalysis方法

public static void runAnalysis(Context context, HeapDump heapDump,
      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    Intent intent = new Intent(context, HeapAnalyzerService.class);
    intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
    intent.putExtra(HEAPDUMP_EXTRA, heapDump);
    context.startService(intent);
  }

  public HeapAnalyzerService() {
    super(HeapAnalyzerService.class.getSimpleName());
  }

  @Override protected void onHandleIntent(Intent intent) {
    if (intent == null) {
      CanaryLog.d("HeapAnalyzerService received a null intent, ignoring.");
      return;
    }
    String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);

    HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs);

    AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
    AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
  }

runAnalysis方法主要作用是开启一个DisplayLeakService服务,然后DisplayLeakService是一个IntentService类,会执行onHandleIntent方法,intent拿到DisplayLeakService和HeapDump类。

然后初始化HeapAnalyzer,调用checkForLeak进行heapDumpFile文件分析,然后将分析的结果信息返回给AnalysisResult,然后看sendResultToListener方法

AbstractAnalysisResultService.java

  public static void sendResultToListener(Context context, String listenerServiceClassName,
      HeapDump heapDump, AnalysisResult result) {
    Class<?> listenerServiceClass;
    try {
      listenerServiceClass = Class.forName(listenerServiceClassName);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    }
    Intent intent = new Intent(context, listenerServiceClass);
    intent.putExtra(HEAP_DUMP_EXTRA, heapDump);
    intent.putExtra(RESULT_EXTRA, result);
    context.startService(intent);
  }

把DisplayLeakService服务传过来传过去的,终于要开启他了,然后我们看DisplayLeakService类

//DisplayLeakService没有初始化操作,只能来看看父类了
public class DisplayLeakService extends AbstractAnalysisResultService 
//是一个IntentService,那我们可以来看onHandleIntent方法
public abstract class AbstractAnalysisResultService extends IntentService 

AbstractAnalysisResultService.java

  @Override protected final void onHandleIntent(Intent intent) {
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAP_DUMP_EXTRA);
    AnalysisResult result = (AnalysisResult) intent.getSerializableExtra(RESULT_EXTRA);
    try {
      onHeapAnalyzed(heapDump, result);
    } finally {
      //noinspection ResultOfMethodCallIgnored
      heapDump.heapDumpFile.delete();
    }
  }

拿到dump分析的结果信息,然后调用onHeapAnalyzed方法,onHeapAnalyzed是一个抽象方法,那么,我们又得回到子类DisplayLeakService去看下onHeapAnalyzed方法。分析完后,finally最后会删除这个分析文件

DisplayLeakService.java

@Override 
protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
    ...
    pendingIntent = DisplayLeakActivity.createPendingIntent(this, heapDump.referenceKey);
    ...

    showNotification(this, contentTitle, contentText, pendingIntent, notificationId);
    afterDefaultHandling(heapDump, result, leakInfo);
   ...
  }

这个里面不重要的东西我就去掉了,很多操作都是在构建通知的信息。
DisplayLeakActivity.createPendingIntent主要是构建通知栏点击打开的Activity,也就是DisplayLeakActivity。
然后,这个地方就是我们平时比较熟知的了,在发生泄漏操作的时候,会显示通知栏。
afterDefaultHandling是一个抽象方法,看注释说明,我们可以去重写这个方法,然后实现我们自己逻辑的一些自定义处理,比如上传到我们自己的服务器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值