square的leakcanary库实现分析

本文详细解析了LeakCanary的实现原理,包括如何通过RefWatcher追踪内存中的对象,利用ActivityLifecycleCallbacks监听Activity销毁过程,以及如何通过GC和堆转储分析确定内存泄漏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Squareup大神公司出品的著名android检测内存泄漏的库,这里不介绍用法。
官网地址https://github.com/square/leakcanary。

官方说明了实现原理。
1 crefWatcher.watch() reates a KeyedWeakReference to the watched object.
2 Later, in a background thread, it checks if the reference has been cleared and if not it triggers a GC.
3 If the reference is still not cleared, it then dumps the heap into a .hprof file stored on the app file system.
4 HeapAnalyzerService is started in a separate process and HeapAnalyzer parses the heap dump using HAHA.
5 HeapAnalyzer finds the keyedWeakReference in the heap dump thanks to a unique reference key and locates the leaking reference.
6 HeapAnalyzer computes the shortest strong reference path to the GC Roots to determine if there is a leak, and then builds the chain of references causing the leak.
7 The result is passed back to DisplayLeakService in the app process, and the leak notification is shown.
其实实现原理说的非常清楚了。
这篇文章看一看代码是怎么具体实现的。

从LeakCanary.install函数开始分析具体实现。
LeakCanary最简单的使用方式就是在application类调用LeakCanary.install(this).

LeakCanary.java
public static RefWatcher install(Application application) {
  return install(application, DisplayLeakService.class,
     AndroidExcludedRefs.createAppDefaults().build());
}
public static RefWatcher install(Application application,
   Class<? extends AbstractAnalysisResultService> listenerServiceClass,
   ExcludedRefs excludedRefs) {
  if (isInAnalyzerProcess(application)) {
   return RefWatcher.DISABLED;
  }
  enableDisplayLeakActivity(application);
  HeapDump.Listener heapDumpListener =
     new ServiceHeapDumpListener(application, listenerServiceClass);
  RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
  ActivityRefWatcher.installOnIcsPlus(application, refWatcher);   //官方文档 ActivityRefWatcher负责检测activity leak
  return refWatcher;  //注意这里是函数返回值 复用refWatcher(这个类可以追踪任何类型的对象(不止是activity
}

看下androidWatcher函数的实现 其实就是一个普通的RefWatcher
public static RefWatcher androidWatcher(Context context, HeapDump.Listener heapDumpListener,
   ExcludedRefs excludedRefs) {
  DebuggerControl debuggerControl = new AndroidDebuggerControl();
  AndroidHeapDumper heapDumper = new AndroidHeapDumper(context);    // heapDumper这个类下文有分析 用来dumper(联想Eclipse的MAT工具
  heapDumper.cleanup();
  return new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT,
     heapDumper, heapDumpListener, excludedRefs);        //这几个类在refWatcher的ensurego函数里被调用
}


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();       //可以看到installOnIcsPlus函数调用了watchActivites来监视activity
}
public void watchActivities() {
  // Make sure you don't get installed twice.
  stopWatchingActivities();
  application.registerActivityLifecycleCallbacks(lifecycleCallbacks);   //activityRefWatcher监视activity的方法就是监听ActivityLifeCleCallback
}

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);  //可以看到leak canary只在activity onDestroyed触发判断是否有内存泄漏
     }
    };
void onActivityDestroyed(Activity activity) {
  refWatcher.watch(activity);    //这里的实现就是官方说的 先触发gc 若触发后仍然没有被clear说明存在内存泄漏
                                    
}

好,通过前面的分析我们看到leakcanary通过添加一个ActivityLifecleCallback的方法在activity onDestroy的时候触发判断是否有内存泄漏。
RefWatcher.java
public void watch(Object watchedReference) {
  watch(watchedReference, "");
}
/**
* Watches the provided references and checks if it can be GCed. This method is non blocking,
* the check is done on the {@link Executor} this {@link RefWatcher} has been constructed with.
*
@param referenceName An logical identifier for the watched object.
*/
public void watch(Object watchedReference, String referenceName) {           
  if (debuggerControl.isDebuggerAttached()) {
   return;
  }
  final long watchStartNanoTime = System.nanoTime();
  String key = UUID.randomUUID().toString();
  retainedKeys.add(key);
  final KeyedWeakReference reference =
     new KeyedWeakReference(watchedReference, key, referenceName, queue);  //使用特殊的技巧打上tag
  watchExecutor.execute(new Runnable() {
   @Override public void run() {
     ensureGone(reference, watchStartNanoTime);
   }
  });
}
void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
  long gcStartNanoTime = System.nanoTime();
  long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
  removeWeaklyReachableReferences();      //使用特殊的技巧remove weaklyrechable的tag
  if (gone(reference) || debuggerControl.isDebuggerAttached()) {
   return;
  }
  gcTrigger.runGc();                                    //触发gc
  removeWeaklyReachableReferences();     //使用特殊的技巧remove weaklyrechable的tag
  if (!gone(reference)) {                            //还没有remove 掉 说明发生内存泄漏
   long startDumpHeap = System.nanoTime();
   long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
    File heapDumpFile = heapDumper.dumpHeap();         
    if (heapDumpFile == HeapDumper.NO_DUMP) {
     // Could not dump the heap, abort.
     return;
   }
  long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
   heapdumpListener.analyze(                    //dump并分析
       new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
           gcDurationMs, heapDumpDurationMs));
  }
}

上文的注释中有分析dump的实现类是AndroidHeapDumper.
AndroidHeapDumper.java
@Override public File dumpHeap() {
  if (!isExternalStorageWritable()) {
  }
  File heapDumpFile = getHeapDumpFile();
  if (heapDumpFile.exists()) {
   return NO_DUMP;
  }
  FutureResult<Toast> waitingForToast = new FutureResult<>();
  showToast(waitingForToast);
  if (!waitingForToast.wait(5, SECONDS)) {
   return NO_DUMP;
  }
  Toast toast = waitingForToast.get();
  try {
   Debug.dumpHprofData(heapDumpFile.getAbsolutePath());   //dump heap 是由系统实现的
   cancelToast(toast);
   return heapDumpFile;
  } catch (Exception e) {
   cleanup();
   return NO_DUMP;
  }
}

ok~这篇文章就先到这里
这篇文章从LeakCanary.install(this)开始分析了leakCanary的关键实现原理。
比如,refWatcher类负责追踪一个对象在内存中是否存在。
refWatcher插入android系统是通过application的 Application.ActivityLifecycleCallbacks接口中的
onDestroy。
refWatcher追踪对象的实现手法是自己保存一个random key的key map,当发现activity对应的这个key
没有被remove时触发gc,gc后仍然存在,则调用android.os.debug api进行dump,然后分析dump出来
的文件。













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值