LeakCanary 中文使用说明

Android 和 Java 内存泄露检测。

“A small leak will sink a great ship.” - Benjamin Franklin

千里之堤, 毁于蚁穴。 -- 《韩非子·喻老》


开始使用

在 build.gradle 中加入引用,不同的编译使用不同的引用:


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. dependencies {  
  2.   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'  
  3.   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'  
  4. }  

在 Application 中:


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. class ExampleApplication extends Application {  
  4.   
  5.   @Override public void onCreate() {  
  6.     super.onCreate();  
  7.     LeakCanary.install(this);  
  8.   }  
  9. }  

这样,就万事俱备了! 在 debug build 中,如果检测到某个 activity 有内存泄露,LeakCanary 就是自动地显示一个通知。

为什么需要使用 LeakCanary?

问得好,看这个文章LeakCanary: 让内存泄露无所遁形

如何使用

使用 RefWatcher 监控那些本该被回收的对象。


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. RefWatcher  
  2.    
  3. refWatcher = {...};  
  4.   
  5. // 监控  
  6. refWatcher.watch(schrodingerCat);  

LeakCanary.install() 会返回一个预定义的 RefWatcher,同时也会启用一个 ActivityRefWatcher,用于自动监控调用Activity.onDestroy() 之后泄露的 activity。


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. class ExampleApplication extends Application {  
  4.   
  5.   public static RefWatcher getRefWatcher(Context context) {  
  6.     ExampleApplication application = (ExampleApplication) context.getApplicationContext();  
  7.     return application.refWatcher;  
  8.   }  
  9.   
  10.   private RefWatcher refWatcher;  
  11.   
  12.   @Override public void onCreate() {  
  13.     super.onCreate();  
  14.     refWatcher = LeakCanary.install(this);  
  15.   }  
  16. }  

使用 RefWatcher 监控 Fragment:


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. abstract class BaseFragment extends Fragment {  
  4.   
  5.   @Override public void onDestroy() {  
  6.     super.onDestroy();  
  7.     RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());  
  8.     refWatcher.watch(this);  
  9.   }  
  10. }  

工作机制

  1. RefWatcher.watch() 创建一个 KeyedWeakReference 到要被监控的对象。

  2. 然后在后台线程检查引用是否被清除,如果没有,调用GC。

  3. 如果引用还是未被清除,把 heap 内存 dump 到 APP 对应的文件系统中的一个 .hprof 文件中。

  4. 在另外一个进程中的 HeapAnalyzerService 有一个 HeapAnalyzer 使用HAHA 解析这个文件。

  5. 得益于唯一的 reference key, HeapAnalyzer 找到 KeyedWeakReference,定位内存泄露。

  6. HeapAnalyzer 计算 到 GC roots 的最短强引用路径,并确定是否是泄露。如果是的话,建立导致泄露的引用链。

  7. 引用链传递到 APP 进程中的 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

你甚至可以通过分享按钮把这些东西分享出去。

SDK 导致的内存泄露

随着时间的推移,很多SDK 和厂商 ROM 中的内存泄露问题已经被尽快修复了。但是,当这样的问题发生时,一般的开发者能做的事情很有限。

LeakCanary 有一个已知问题的忽略列表,AndroidExcludedRefs.java,如果你发现了一个新的问题,请提一个 issue 并附上 leak trace, reference key, 机器型号和 SDK 版本。如果可以附带上 dump 文件的 链接那就再好不过了。

对于最新发布的 Android,这点尤其重要。你有机会在帮助在早期发现新的内存泄露,这对整个 Android 社区都有极大的益处。

开发版本的 Snapshots 包在这里: Sonatype's snapshots repository

leak trace 之外

有时,leak trace 不够,你需要通过 MAT 或者 YourKit 深挖 dump 文件。

通过以下方法,你能找到问题所在:

  1. 查找所有的 com.squareup.leakcanary.KeyedWeakReference 实例。
  2. 检查 key 字段
  3. Find the KeyedWeakReference that has a key field equal to the reference key reported by LeakCanary.
  4. 找到 key 和 和 logcat 输出的 key 值一样的 KeyedWeakReference
  5. referent 字段对应的就是泄露的对象。
  6. 剩下的,就是动手修复了。最好是检查到 GC root 的最短强引用路径开始。

自定义

UI 样式

DisplayLeakActivity 有一个默认的图标和标签,你只要在你自己的 APP 资源中,替换以下资源就可。


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. res/  
  2.   drawable-hdpi/  
  3.     __leak_canary_icon.png  
  4.   drawable-mdpi/  
  5.     __leak_canary_icon.png  
  6.   drawable-xhdpi/  
  7.     __leak_canary_icon.png  
  8.   drawable-xxhdpi/  
  9.     __leak_canary_icon.png  
  10.   drawable-xxxhdpi/  
  11.     __leak_canary_icon.png  
  12. <?xml version="1.0" encoding="utf-8"?>  
  13.   
  14. <resources>  
  15.   <string name="__leak_canary_display_activity_label">MyLeaks</string>  
  16. </resources>  
保存 leak trace

DisplayLeakActivity saves up to 7 heap dumps & leak traces in the app directory. You can change that number by providingR.integer.__leak_canary_max_stored_leaks in your app:

在 APP 的目录中,DisplayLeakActivity 保存了 7 个 dump 文件和 leak trace。你可以在你的 APP 中,定义R.integer.__leak_canary_max_stored_leaks 来覆盖类库的默认值。


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <resources>  
  4.   <integer name="__leak_canary_max_stored_leaks">20</integer>  
  5. </resources>  
上传 leak trace 到服务器

你可以改变处理完成的默认行为,将 leak trace 和 heap dump 上传到你的服务器以便统计分析。

创建一个 LeakUploadService, 最简单的就是继承 DisplayLeakService :


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. class LeakUploadService extends DisplayLeakService {  
  4.   @Override  
  5.   protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {  
  6.     if (!result.leakFound || result.excludedLeak) {  
  7.       return;  
  8.     }  
  9.     myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo);  
  10.   }  
  11. }  

请确认 release 版本 使用 RefWatcher.DISABLED


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. class ExampleApplication extends Application {  
  4.   
  5.   public static RefWatcher getRefWatcher(Context context) {  
  6.     ExampleApplication application = (ExampleApplication) context.getApplicationContext();  
  7.     return application.refWatcher;  
  8.   }  
  9.   
  10.   private RefWatcher refWatcher;  
  11.   
  12.   @Override public void onCreate() {  
  13.     super.onCreate();  
  14.     refWatcher = installLeakCanary();  
  15.   }  
  16.   
  17.   protected RefWatcher installLeakCanary() {  
  18.     return RefWatcher.DISABLED;  
  19.   }  
  20. }  

自定义 RefWatcher


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. public  
  2.    
  3. class DebugExampleApplication extends ExampleApplication {  
  4.   protected RefWatcher installLeakCanary() {  
  5.     return LeakCanary.install(app, LeakUploadService.class);  
  6.   }  
  7. }  

别忘了注册 service:


  
  
[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <manifest  
  4. xmlns:android=  
  5. "http://schemas.android.com/apk/res/android"     
  6. xmlns:tools=  
  7. "http://schemas.android.com/tools"      
  8. >  
  9.     
  10. <application  
  11. android:name=  
  12. "com.example.DebugExampleApplication"  
  13. >  
  14.       
  15. <service  
  16. android:name=  
  17. "com.example.LeakUploadService"  
  18. />  
  19.     
  20. </application>  
  21.   
  22. </manifest>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeakCanary是一个用于检测Android应用程序内存泄漏的开源库。它可以帮助开发者在开发和测试过程中快速发现和解决内存泄漏问题。 要使用LeakCanary,您需要在您的Android项目中添加以下依赖项(在您的build.gradle文件的dependencies部分): ``` debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.x.x' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.x.x' ``` 接下来,在您的Application类中初始化LeakCanary: ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // 这个进程是用于LeakCanary分析的,不执行LeakCanary的初始化操作 return; } LeakCanary.install(this); } } ``` LeakCanary会自动检测您的应用程序中的内存泄漏,并在检测到泄漏时提供详细的报告。当您运行应用程序时,如果发现内存泄漏,LeakCanary会在通知栏中显示一个通知,并在您的应用程序退出时显示一个通知。 通过分析LeakCanary提供的报告,您可以确定内存泄漏的原因,并采取相应的措施来解决问题,例如释放对象引用、取消注册监听器等。 请注意,LeakCanary仅在调试构建中生效,不会影响发布版本的性能。因此,在发布应用程序之前,请确保将LeakCanary从releaseImplementation更改为leakcanary-android-no-op。 希望这个简单的介绍对您有帮助!如果您有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值