LeakCanary 源码解析

LeakCanary 是什么?

LeakCanary是Square公司基于MAT开源的一个工具,用来检测Android App中的内存泄露问题。官方地址:https://github.com/square/leakcanary

工作原理分析:

1.怎么检测内存泄漏?什么时候去检测内存泄漏?

//注册生命周期  在onDestory 的时候 观察Activity 对象
 private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new ActivityLifecycleCallbacksAdapter() {
        @Override public void onActivityDestroyed(Activity activity) {
        	//开始观察
          refWatcher.watch(activity);
        }
      };



	// 此方法为停止观察activity  也就是不在监听回掉
  public void stopWatchingActivities() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
  }

自己去跟源码就会发现,LeakCanary 会 注册一个ActivityLifecycleCallbacks ,当监听到activity Ondestory 的时候,就会去观察这个activity 是不是泄漏了,有没有被GC回收。

具体怎么观察Activity 有没有被回收?

  /**
   * Watches the provided references and checks if it can be GCed. This method is non blocking,
   * the check is done on the {@link WatchExecutor} this {@link RefWatcher} has been constructed
   * with.
   *
   * @param referenceName An logical identifier for the watched object.
   */
  public void watch(Object watchedReference, String referenceName) {
    if (this == DISABLED) {
      return;
    }
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");
    final long watchStartNanoTime = System.nanoTime();
    String key = UUID.randomUUID().toString();
    retainedKeys.add(key);
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

    ensureGoneAsync(watchStartNanoTime, reference);
  }


  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)) {
      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);

      HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
          .referenceName(reference.name)
          .watchDurationMs(watchDurationMs)
          .gcDurationMs(gcDurationMs)
          .heapDumpDurationMs(heapDumpDurationMs)
          .build();

      heapdumpListener.analyze(heapDump);
    }
    return DONE;
  }

我们看到,观察activity 就是 把 activity 放到WeakRefence 里面,WeakReference 的第二个参数是一个Qeue 对象,我们手动执行一下GC,然后Qeue.pull 一下,看看Qeue 里面是不是有WeakRefence ,如果有说明对象被回收了。那么这个activity 就没有泄漏,否则就有可能泄露了导致回收不了。

这个机制是WeakReference 的机制。有兴趣可以自行了解一下。

怎么执行GC?

      Runtime.getRuntime().gc();
      enqueueReferences();
      System.runFinalization();

上面diam执行之后,我们再看下内存,还有没有activity 的实例,如果还有,那么说明这个activity 可能被泄露了。我们需要根据hprof 文件看下具体的调用链。

怎么生成hprof?

如果activity 内存泄露了,我们需要hprof 文件去分析。那么怎么拿到hprof?

Debug.dumpHprofData(heapDumpFile.getAbsolutePath());

怎么分析hprof

使用了下面的开源项目:

  implementation 'com.squareup.haha:haha:2.0.4'

分析完之后,用界面显示出来就没有什么好说了。

怎么在桌面有两个图标?

    <activity
        android:label="@string/app_name"
        android:name=".MainActivity"
        >
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    </activity>

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

我们发现,leackCanary会生成一个自己的桌面图标,点击进去可以查看内漏泄露的信息,而且不需要创建桌面快捷方式的权限,就可以做到,他是用上面的方式做到的。清单里面可以有多个"android.intent.category.LAUNCHER",当然也会有一个默认的。

怎么设置组件启用和关闭

  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);
  }

也就这样啦,没有具体怎么分析hprof,有兴趣可以再深入研究了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值