LeakCanary,Android内存泄露处理利器
2016-08-01 16:35
267 查看
本篇博文转自黑月神话,原文链接黑月神话
在以前的文章中我讲到过如何使用eclipse和MAT分析内存泄漏(Android内存泄漏分析实战),但是这样的分析往往发生在内存泄漏之后,只能是亡羊补牢。那么我们能不能更早的发现内存泄漏呢?答案是肯定的,LeakCanary能够做到。延伸阅读(LeakCanary源码解析)
什么是LeakCanary
开始使用
debug版本和realse版本用不同的依赖库。由于国内被墙的原因Maven没办法用,导致Android Studio使用不便。所以我自己整合了一个适合eclipse的LeakCanary的库,代码托管在github上面。项目地址:https://github.com/mooncong/Leakcanary-lib.git
那么接下来,LeakCanary将会在debug版本中自动探测内存泄漏,当发生内存泄漏的时候就会在通知栏显示一个通知。
什么是内存泄露
对象在其生命周期内完成使命之后,我们就希望这些对象被回收掉。但是如果还存在对象的引用,那么这个对象将不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。
比如,当Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后因为 OOM 而 crash。
如何使用
使用RefWatcher监控本应该被垃圾回收器回收的对象
LeakCanary.install()返回一个预定义的RefWatcher。它将启动一个ActivityRefWatcher,在Activity.onDestroy()方法调用之后,自动探测Activity的内存泄漏。(注:只支持ICS及以后的版本,具体原因详见代码)
也可以使用RefWatcher探测Fragment泄漏
LeakCanary工作原理
RefWatcher.watch()创建一个KeyedWeakReference到北监控的对象。
接下来,在后台线程中检测这个引用是否被清除,如果没有将会触发GC。
如果引用仍然没有清除,将heap内存dump到一个.hprof的文件存放到手机系统里。
HeapAnalyzerService在另外一个独立的进程中启动,使用HeapAnalyzer解析heap内存通过HAHA这个项目
HeapAnalyzer计算出到GC ROOTs的最短强引用路径决定是否发生Leak,然后建立导致泄漏的引用链。
结果被回传到应用程序进程的DisplayLeakService中,然后显示一个泄漏的通知。
如何复制leak trace
在logcat中可以看见leak trace
也可以从Action bar分享leak trace和heap内存文件。
如何修复内存泄漏?
一旦发生内存泄漏,找出哪一个引用不应该存在。然后分析为什么它还存在。通常它是一个注册的监听器没有被反注册,或者是close()方法没有调用,一个匿名内部类持有了一个外部类的引用,等等。
Android SDK导致的内存泄漏
在过去的日子里,很多内存泄漏已经被修复了,但是当泄漏发生的时候,普通的应用开发很难去修复它。因此,LeakCanary已经建立了一个已知问题的列表,AndroidExcludedRefs.java。如果你发现一个新问题。请提交一个issue并附上Leak trace,reference key,设备和系统版本。要是附上heap文件的链接就更好了。在新发布的Android版本中尤其重要。你有机会帮助尽早的发现内存泄漏,那将会有益于整个Android社区。
Leak trace之外
有时候Leak trace不能够,可以使用MAT或者YourKit深挖dump文件。MAT使用可以参考以前的一片文章Android内存泄漏分析实战
找到所有的com.squareup.leakcanary.KeyedWeakReference实例。
查看他们的每一个key值。
找到key字段等于LeakCanary报告的引用key的KeyedWeakReference。
KeyedWeakReference的referent字段就是泄漏的对象。
接下来,就是动手修复了。最好是检查到 GC root 的最短强引用路径开始。
保持Leak traces
DisplayLeakActivity默认保存7个heap dumps和leak traces,可以通过下面的配置自定义。
上传 leak trace 到服务器
你可以改变处理完成的默认行为,将 leak trace 和 heap dump 上传到你的服务器以便统计分析。 创建一个 AbstractAnalysisResultService,最简单的就是继承 DefaultAnalysisResultService
请确认Realse版本的应用使用RefWatcher.DISABLED
自定义RefWatcher
不要忘记在manifest中注册Service
demo
LeakCanary实战,包含eclipse整合的lib库,以及实例代码。运行代码之后,按照界面提示操作几次,稍等几秒,你将会在通知栏看到一个内存泄漏的通知。
在以前的文章中我讲到过如何使用eclipse和MAT分析内存泄漏(Android内存泄漏分析实战),但是这样的分析往往发生在内存泄漏之后,只能是亡羊补牢。那么我们能不能更早的发现内存泄漏呢?答案是肯定的,LeakCanary能够做到。延伸阅读(LeakCanary源码解析)
什么是LeakCanary
LeakCanary是一个用于检测内存泄漏的工具,可以用于Java和Android,是由著名开源组织Square贡献。
开始使用
debug版本和realse版本用不同的依赖库。由于国内被墙的原因Maven没办法用,导致Android Studio使用不便。所以我自己整合了一个适合eclipse的LeakCanary的库,代码托管在github上面。项目地址:https://github.com/mooncong/Leakcanary-lib.git
dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3' }
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }
那么接下来,LeakCanary将会在debug版本中自动探测内存泄漏,当发生内存泄漏的时候就会在通知栏显示一个通知。
什么是内存泄露
对象在其生命周期内完成使命之后,我们就希望这些对象被回收掉。但是如果还存在对象的引用,那么这个对象将不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。
比如,当Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后因为 OOM 而 crash。
如何使用
使用RefWatcher监控本应该被垃圾回收器回收的对象
RefWatcher refWatcher = {...}; // 监控一个object对象 refWatcher.watch(object);
LeakCanary.install()返回一个预定义的RefWatcher。它将启动一个ActivityRefWatcher,在Activity.onDestroy()方法调用之后,自动探测Activity的内存泄漏。(注:只支持ICS及以后的版本,具体原因详见代码)
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探测Fragment泄漏
public abstract class BaseFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity()); refWatcher.watch(this); } }
LeakCanary工作原理
RefWatcher.watch()创建一个KeyedWeakReference到北监控的对象。
接下来,在后台线程中检测这个引用是否被清除,如果没有将会触发GC。
如果引用仍然没有清除,将heap内存dump到一个.hprof的文件存放到手机系统里。
HeapAnalyzerService在另外一个独立的进程中启动,使用HeapAnalyzer解析heap内存通过HAHA这个项目
HeapAnalyzer计算出到GC ROOTs的最短强引用路径决定是否发生Leak,然后建立导致泄漏的引用链。
结果被回传到应用程序进程的DisplayLeakService中,然后显示一个泄漏的通知。
如何复制leak trace
在logcat中可以看见leak trace
In com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity has leaked: * GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #1') * references com.example.leakcanary.MainActivity$3.this$0 (anonymous class extends android.os.AsyncTask) * leaks com.example.leakcanary.MainActivity instance * Reference Key: e71f3bf5-d786-4145-8539-584afaecad1d * Device: Genymotion generic Google Nexus 6 - 5.1.0 - API 22 - 1440x2560 vbox86p * Android Version: 5.1 API: 22 * Durations: watch=5086ms, gc=110ms, heap dump=435ms, analysis=2086ms
也可以从Action bar分享leak trace和heap内存文件。
如何修复内存泄漏?
一旦发生内存泄漏,找出哪一个引用不应该存在。然后分析为什么它还存在。通常它是一个注册的监听器没有被反注册,或者是close()方法没有调用,一个匿名内部类持有了一个外部类的引用,等等。
Android SDK导致的内存泄漏
在过去的日子里,很多内存泄漏已经被修复了,但是当泄漏发生的时候,普通的应用开发很难去修复它。因此,LeakCanary已经建立了一个已知问题的列表,AndroidExcludedRefs.java。如果你发现一个新问题。请提交一个issue并附上Leak trace,reference key,设备和系统版本。要是附上heap文件的链接就更好了。在新发布的Android版本中尤其重要。你有机会帮助尽早的发现内存泄漏,那将会有益于整个Android社区。
Leak trace之外
有时候Leak trace不能够,可以使用MAT或者YourKit深挖dump文件。MAT使用可以参考以前的一片文章Android内存泄漏分析实战
找到所有的com.squareup.leakcanary.KeyedWeakReference实例。
查看他们的每一个key值。
找到key字段等于LeakCanary报告的引用key的KeyedWeakReference。
KeyedWeakReference的referent字段就是泄漏的对象。
接下来,就是动手修复了。最好是检查到 GC root 的最短强引用路径开始。
保持Leak traces
DisplayLeakActivity默认保存7个heap dumps和leak traces,可以通过下面的配置自定义。
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="__leak_canary_max_stored_leaks">20</integer> </resources>
上传 leak trace 到服务器
你可以改变处理完成的默认行为,将 leak trace 和 heap dump 上传到你的服务器以便统计分析。 创建一个 AbstractAnalysisResultService,最简单的就是继承 DefaultAnalysisResultService
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); } }
请确认Realse版本的应用使用RefWatcher.DISABLED
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; } }
自定义RefWatcher
public class DebugExampleApplication extends ExampleApplication { protected RefWatcher installLeakCanary() { return LeakCanary.install(app, LeakUploadService.class); } }
不要忘记在manifest中注册Service
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.androi.com/tools" > <application android:name="com.example.DebugExampleApplication"> <service android:name="com.example.LeakUploadService" /> </application> </manifest>
demo
LeakCanary实战,包含eclipse整合的lib库,以及实例代码。运行代码之后,按照界面提示操作几次,稍等几秒,你将会在通知栏看到一个内存泄漏的通知。
相关文章推荐
- Android 内存泄露测试数据处理--procrank,setprop,getprop(转)
- Android 内存泄露检测工具 LeakCanary
- 【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的内存泄露。
- 56、LeakCanary——直白的展现Android中的内存泄露
- Android 和 Java 内存泄露检测工具--LeakCanary
- Android内存泄露抓取工具leakcanary
- Android内存泄露利器MLT(整合篇)
- LeakCanary Android 和 Java 内存泄露检测
- android内存泄露监测之leakcanary
- Android监控内存泄露利器-使用Leak Canary
- android 内存泄露浅谈和处理
- 【android】通过leakCanary找出程序内存泄露点
- Android 处理内存泄露的方法
- Android内存泄露分析和处理
- Android 内存泄露测试数据处理--procrank,setprop,getprop
- Android 处理内存泄露的方法
- Android 使用LeakCanary 检测内存泄露
- Android 使用LeakCanary 检测内存泄露
- Android内存泄露检测工具---LeakCanary的前世今生
- Android 中 Handler 引起的内存泄露 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何