美文网首页
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原理浅析

    LeakCanary原理浅析 1.LeakCanary简介 LeakCanary是一个Android和Java的内...

  • LeakCanary 工作原理浅析

    参考链接Java内存问题 及 LeakCanary 原理分析LeakCanary 工作原理浅析 通过 appli...

  • LeakCanary浅析

    一、使用 LeakCanary的使用非常的简单,两行代码搞定。当然也可以主动的添加需要监听的对象;LeakCana...

  • LeakCanary浅析

    说到内存泄漏,就必须提到LeakCanary. 这个利器,很方便的显示出内存泄漏的地方。在用到的过程中好奇怎...

  • LeakCanary浅析

    前提:LeakCanary 版本v2.4; Android 8.0LeakCanary相信很多开发者都用过,也是目...

  • Leakcanary浅析

    本文主要分析内存泄漏的检测原理和如何实现生产环境应用,代码分析基于Leakcanary 1.6版本。 如何检测内存...

  • LeakCanary源码浅析

    LeakCanary是Square公司的找出内存泄露工具 LeakCanary简单介绍 Square 最新发布的一...

  • LeakCanary源码浅析

    在Android开发中最让人们头疼的就是内存泄漏了,今天来介绍一个查看内存是否泄漏的工具LeakCanary,并通...

  • LeakCanary原理浅析

    LeakCanary是Android内存泄漏的框架,作为一个“面试常见问题”,它一定有值得学习的地方,今天我们就讲...

  • LeakCanary 工作原理浅析

    版权声明:本文为 咕咚 原创文章,可以随意转载,但必须在明确位置注明出处。作者博客地址: http://gudon...

网友评论

      本文标题:LeakCanary浅析

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