当前位置:首页 > 开发教程 > 手机开发 >

内存泄漏检测库针对Android和Java。

时间:2016-02-16 11:20 来源:互联网 作者:源码搜藏 收藏

LeakCanary 内存泄漏检测库针对 Android 和Java。 小不忍则乱大谋。 -本杰明富兰克林 入门 在你 的build.gradle : dependencies { debugCompile com.squareup.leakcanary:leakcanary-android:1.3.1 // or 1.4-beta1 releaseCompile com.squareup.leakcanary

LeakCanary

内存泄漏检测库针对Android和Java。

“小不忍则乱大谋。” -本杰明·富兰克林

内存泄漏检测库针对Android和Java。

入门

在你的build.gradle


	
 dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' // or 1.4-beta1
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
 }

在您的应用程序类:


	
public class ExampleApplication extends Application {

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

你是好去!当你的调试版本检测到活动内存泄漏LeakCanary会自动显示一个通知。

为什么要使用LeakCanary?

很高兴你问!我们写了一篇博客文章正是要回答这个问题。

我如何使用它?

使用RefWatcher看,应该是GCed引用:


	
RefWatcher refWatcher = {...};

// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);

LeakCanary.install()返回配置的预RefWatcher它还安装了ActivityRefWatcher如果活动泄漏后,可以自动检测Activity.onDestroy()被调用。


	
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();
    refWatcher = LeakCanary.install(this);
  }
}

您可以使用RefWatcher观看的片段泄漏:


	
public abstract class BaseFragment extends Fragment {

  @Override public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
    refWatcher.watch(this);
  }
}

它是如何工作的?

  1. RefWatcher.watch()创建一个KeyedWeakReference到监视对象。
  2. 后来,在后台线程,它会检查是否引用已被清除,如果没有它触发GC。
  3. 如果参考仍未清除,它会转储堆到.hprof存储应用程序的文件系统上的文件。
  4. HeapAnalyzerService是在一个单独的进程开始,HeapAnalyzer使用解析堆转储HAHA
  5. HeapAnalyzer发现KeyedWeakReference堆转储由于采用了独特的引用键和定位泄漏参考。
  6. HeapAnalyzer计算最短强参考路径到GC罗茨,以确定是否存在泄漏,然后生成引起泄漏的引用链。
  7. 将结果传回给DisplayLeakService在应用过程中,和泄漏通知被示出。

如何复制泄漏痕迹?

你可以看到在logcat的泄漏跟踪:

在com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity渗漏:
* GC线程ROOT的java.lang.Thread。<Java的地方>(命名为“AsyncTask的#1”)
*引用com.example.leakcanary.MainActivity $ 3,本$ 0(匿名类扩展android.os.AsyncTask)
*泄漏com.example.leakcanary.MainActivity实例

*参考键:e71f3bf5-d786-4145-8539-584afaecad1d
*设备:Genymotion通用谷歌Nexus 6  -  5.1.0  -  API 22  -  1440x2560 vbox86p
*的Android版本:5.1 API:22
*持续时间:观看= 5086ms,GC = 110毫秒,堆转储= 435ms,分析= 2086ms

你也可以分享泄漏跟踪,并从堆转储文件操作栏菜单

如何解决内存泄漏?

一旦你有泄漏痕迹,找出哪些路径参考不应该存在。然后弄清楚为什么该引用仍然存在。很多时候,这是一个注册的侦听器应该是未注册的,一个close()方法是不叫的方法,即持有引用外部类匿名类。如果你不能在你的代码中找出问题,请不要提交问题相反,创建一个堆栈溢出问题(使用leakcanary标签)。

我的泄漏是由Android SDK的实施造成的!

有许多已经在AOSP以及在制造商实现了固定的一段时间内已知的内存泄漏。当这样的泄漏发生时,有一点你可以做一个应用程序开发人员来修复它。出于这个原因,LeakCanary具有已知的Android泄漏的内置列表忽略:AndroidExcludedRefs.java

如果你找到一个新的,请创建一个问题,并按照下列步骤操作:

  1. 提供整个泄漏跟踪信息(参考键,设备等)。
  2. 阅读该版本的Android的AOSP源代码,并试图弄清楚为什么会发生。您可以通过SDK版本轻松浏览的Android / platform_frameworks_base
  3. 检查是否发生在Android的最新版本,并以其他方式使用怪发现,当它被固定的。
  4. 如果问题仍然发生,构建一个简单的摄制情况
  5. 文件中的问题上b.android.com与泄漏跟踪和摄制情况
  6. 创建LeakCanary公关更新AndroidExcludedRefs.java可选:如果你发现一个黑客以清除在Android的早期版本的泄漏,随时记录下来。

这是特别重要的Android的新版本你有机会来帮助发现早期新的内存泄漏,这有利于整个Android社区。

除了微量泄漏

有时漏痕迹是不够的,你需要挖掘与堆转储MATYourKit这里是你如何能找到头部转储泄漏实例:

  1. 寻找的所有实例com.squareup.leakcanary.KeyedWeakReference
  2. 对于这些,看关键领域。
  3. 找到KeyedWeakReference具有字段等于由LeakCanary报告的参考键。
  4. 指涉的领域KeyedWeakReference是你的泄漏对象。
  5. 从此,此事是在你的手中。一个良好的开端是看的最短路径的GC根(不含弱引用)。

定制

定制并使用无操作的依赖

leakcanary-Android的无操作释放依赖构建只包含LeakCanaryRefWatcher类。如果你开始自定义LeakCanary,你需要确保定制只发生在调试版本,因为它可能会引用不存在的类leakcanary-Android的无操作的依赖。

比方说,你的发布版本声明一个ExampleApplicationAndroidManifest.xml中,你的调试版本声明了一个DebugExampleApplication扩展ExampleApplication

在您的共享资源:


	
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();
    refWatcher = installLeakCanary();
  }

  protected RefWatcher installLeakCanary() {
    return RefWatcher.DISABLED;
  }
}

在调试来源:


	
public class DebugExampleApplication extends ExampleApplication {
  protected RefWatcher installLeakCanary() {
    RefWatcher refWatcher =  // Build a customized RefWatcher
    return refWatcher;
  }
}

这样一来,你的发布代码将包含不超过存在于两个空类等参考LeakCanary leakcanary-Android的无操作的依赖。

图标和标签

DisplayLeakActivity自带的默认图标和标签,您可以通过提供改变R.drawable .__ leak_canary_iconR.string .__ leak_canary_display_activity_label在您的应用程序:


res/
  drawable-hdpi/
    __leak_canary_icon.png
  drawable-mdpi/
    __leak_canary_icon.png
  drawable-xhdpi/
    __leak_canary_icon.png
  drawable-xxhdpi/
    __leak_canary_icon.png
  drawable-xxxhdpi/
    __leak_canary_icon.png
<xml version="1.0" encoding="utf-8">
<resources>
  <string name="__leak_canary_display_activity_label">MyLeaks</string>
</resources>

存储泄漏的痕迹

DisplayLeakActivity节省多达7堆转储和泄漏的痕迹在app目录。您可以通过提供改变这个数字R.integer .__ leak_canary_max_stored_leaks在您的应用程序:


	
<xml version="1.0" encoding="utf-8">
<resources>
  <integer name="__leak_canary_max_stored_leaks">20</integer>
</resources>

守望延迟

可在1.4-SNAPSHOT

直到参考被认为提供了内存泄漏,您可以更改延迟R.integer.leak_canary_watch_delay_millis在您的应用程序:


	
<xml version="1.0" encoding="utf-8">
<resources>
  <integer name="leak_canary_watch_delay_millis">1500</integer>
</resources>

默认延迟为5秒。

上传到服务器

您可以更改默认行为泄漏跟踪和堆转储上传到您选择的服务器。

创建您自己的AbstractAnalysisResultService最简单的方法是延长DisplayLeakService在调试来源:


	
public class LeakUploadService extends DisplayLeakService {
  @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
    if (!result.leakFound || result.excludedLeak) {
      return;
    }
    myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo);
  }
}

建立一个自定义RefWatcher在调试应用程序类:

// ExampleApplication在“自定义定义和使用无操作dependency" 
public  class  DebugExampleApplication  extends  ExampleApplication {
   protected  RefWatcher  installLeakCanary () {
     return  LeakCanary . install(app, LeakUploadService . class, AndroidExcludedRefs . createAppDefaults() . build());
  }
}

不要忘记在调试注册服务的AndroidManifest.xml


	
<xml version="1.0" encoding="utf-8">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >
  <application android:name="com.example.DebugExampleApplication">
    <service android:name="com.example.LeakUploadService" />
  </application>
</manifest>

您也可以上传泄漏痕迹,松弛或HipChat,这里是一个例子

忽略具体引用

你可以创建自己的版本ExcludedRefs忽略你知道是造成泄漏,但你仍然想要忽略具体的参考:

// ExampleApplication在“自定义定义和使用无操作 
public class DebugExampleApplication extends ExampleApplication {
  protected RefWatcher installLeakCanary() {
    ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults()
        .instanceField("com.example.ExampleClass", "exampleField")
        .build();
    return LeakCanary.install(this, DisplayLeakService.class, excludedRefs);
  }
}

不看具体的活动课

ActivityRefWatcher是默认安装和手表的所有活动。您可以自定义安装步骤,使用不同的东西来代替:

// ExampleApplication在“自定义定义和使用无操作 
  public class DebugExampleApplication extends ExampleApplication {
  @Override protected RefWatcher installLeakCanary() {
    if (LeakCanary.isInAnalyzerProcess(this)) {
      return RefWatcher.DISABLED;
    } else {
      ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults().build();
      LeakCanary.enableDisplayLeakActivity(this);
      ServiceHeapDumpListener heapDumpListener = new ServiceHeapDumpListener(this, DisplayLeakService.class);
      final RefWatcher refWatcher = LeakCanary.androidWatcher(this, heapDumpListener, excludedRefs);
      registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        public void onActivityDestroyed(Activity activity) {
          if (activity instanceof ThirdPartyActivity) {
              return;
          }
          refWatcher.watch(activity);
        }
        // ...
      });
      return refWatcher;
    }
  }
}

开发版快照

查看更新日志

故障排除

  • 如果leakcanary-的Android是不是在Android Studio中的外部库的列表,但leakcanary分析仪leakcanary观察家在那里:尝试做一个干净的构建如果它仍然是一个问题,尝试在命令行建设。
  • 错误:包com.squareup.leakcanary不存在:如果你有其他类型的建设比调试释放,你需要添加一个特定的依赖也为它们(xxxCompile)。

库下载地址https://github.com/square/leakcanary
资源


手机开发阅读排行

最新文章