LeakCanary浅析

一、使用

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 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 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 listenerServiceClass) {
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}

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

public ServiceHeapDumpListener(Context context,
  Class 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浅析)