经典的面试题:

a、怎样在coding过程中避免内存泄露?

b、怎样检测内存泄露?

这两个问题我想大部分​​Android​​ 职位面试时都会被问到吧。

        怎样避免就不赘述了,网上很多答案。

       工具呢,当然也有很多,比如DDMS、MAT等,但是怎样在我们编码过程中植入内存检测代码,让我们程序在开发调试阶段就能发现内存泄露呢?好了,现在该大名鼎鼎的LeakCanary出场了,它是Square公司的一个内存探测开源项目。下面就介绍下怎样使用.


1、配置gradle依赖:    




[java]​view plain​​ ​​copy​


  1. debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'  
  2. releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'  


2、初始化Watcher




[java]​view plain​​ ​​copy​


  1. package com.micky.leakcanarysamples;;  
  2.   
  3. import android.app.Application;  
  4.   
  5. import com.squareup.leakcanary.LeakCanary;  
  6. import com.squareup.leakcanary.RefWatcher;  
  7.   
  8. /** 
  9.  * @Project LeakCanaryTest 
  10.  * @Packate com.micky.leakcanarysamples; 
  11.  * @Description 
  12.  * @Author Micky Liu 
  13.  * @Email mickyliu@126.com 
  14.  * @Date 2016-01-04 10:32 
  15.  * @Version 1.0 
  16.  */  
  17. public class BaseApplication extends Application {  
  18.   
  19.     private static BaseApplication instance;  
  20.   
  21.     private RefWatcher mRefWatcher;  
  22.   
  23.     @Override  
  24.     public void onCreate() {  
  25.         super.onCreate();  
  26.         instance = this;  
  27.         mRefWatcher = Constants.DEBUG ?  LeakCanary.install(this) : RefWatcher.DISABLED;  
  28.     }  
  29.   
  30.     public static BaseApplication getInstance() {  
  31.         return instance;  
  32.     }  
  33.   
  34.     public static RefWatcher getRefWatcher() {  
  35.         return getInstance().mRefWatcher;  
  36.     }  
  37. }  



3、在Activity或Fragment中添加检测




[java]​view plain​​ ​​copy​


  1. package com.micky.leakcanarysamples;  
  2.   
  3. import android.app.Activity;  
  4. import android.support.v7.app.AppCompatActivity;  
  5.   
  6. /** 
  7.  * @Project LeakCanaryTest 
  8.  * @Packate com.micky.leakcanarysamples; 
  9.  * @Description 
  10.  * @Author Micky Liu 
  11.  * @Email mickyliu@126.com 
  12.  * @Date 2016-01-04 10:39 
  13.  * @Version 1.0 
  14.  */  
  15. public class BaseActivity extends AppCompatActivity {  
  16.   
  17.     @Override  
  18.     protected void onDestroy() {  
  19.         super.onDestroy();  
  20.         BaseApplication.getRefWatcher().watch(this);  
  21.     }  
  22. }  


4、测试



[java]​view plain​​ ​​copy​


  1. package com.micky.leakcanarysamples;;  
  2.   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5.   
  6. /** 
  7.  * @Project LeakCanaryTest 
  8.  * @Packate com.micky.leakcanarysamples; 
  9.  * @Description 
  10.  * @Author Micky Liu 
  11.  * @Email mickyliu@126.com 
  12.  * @Date 2016-01-04 10:29 
  13.  * @Version 1.0 
  14.  */  
  15. public class TestActivity extends BaseActivity {  
  16.   
  17.     private final Handler mHandler = new Handler();  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         //模拟内存泄露  
  23.         mHandler.postDelayed(new Runnable() {  
  24.             @Override  
  25.             public void run() {  
  26.   
  27.             }  
  28.         }, 3 * 60 * 1000);  
  29.         finish();  
  30.     }  
  31. }  



5、测试结果

a、Toast显示(大概10秒左右显示)

Android内存泄露自动检测神器LeakCanary_android


b、通知显示

Android内存泄露自动检测神器LeakCanary_ide_02


c、桌面自动添加的图表

Android内存泄露自动检测神器LeakCanary_java_03


d、内存泄露列表

Android内存泄露自动检测神器LeakCanary_java_04


e、内存泄露详细

Android内存泄露自动检测神器LeakCanary_内存泄露_05


LogCat可以看到日志日下(hprof文件可以用MAT打开进行分析):




[html]​view plain​​ ​​copy​


  1. 01-04 11:49:41.815 12967-13004/com.micky.leakcanarysamples I/dalvikvm: hprof: dumping heap strings to "/storage/emulated/0/Download/leakcanary/suspected_leak_heapdump.hprof".  
  2. 01-04 11:49:42.020 12967-13004/com.micky.leakcanarysamples I/dalvikvm: hprof: heap dump completed (28850KB)  



查看自动生成的AndroidManifest文件,LeakCanarySamples/app/build/intermediates/manifests/full/debug/AndroidManifest.xml




[html]​view plain​​ ​​copy​


  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.micky.leakcanarysamples"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="10"  
  9.         android:targetSdkVersion="23" />  
  10.   
  11.     <!-- To store the heap dumps and leak analysis results. -->  
  12.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  13.   
  14.     <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
  15.   
  16.     <application  
  17.         android:name="com.micky.leakcanarysamples.BaseApplication"  
  18.         android:allowBackup="true"  
  19.         android:icon="@mipmap/ic_launcher"  
  20.         android:label="@string/app_name"  
  21.         android:supportsRtl="true"  
  22.         android:theme="@style/AppTheme" >  
  23.         <activity  
  24.             android:name="com.micky.leakcanarysamples.MainActivity"  
  25.             android:label="@string/app_name"  
  26.             android:theme="@style/AppTheme.NoActionBar" >  
  27.             <intent-filter>  
  28.                 <action android:name="android.intent.action.MAIN" />  
  29.   
  30.                 <category android:name="android.intent.category.LAUNCHER" />  
  31.             </intent-filter>  
  32.         </activity>  
  33.         <activity android:name="com.micky.leakcanarysamples.TestActivity" />  
  34.   
  35.         <service  
  36.             android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"  
  37.             android:enabled="false"  
  38.             android:process=":leakcanary" />  
  39.         <service  
  40.             android:name="com.squareup.leakcanary.DisplayLeakService"  
  41.             android:enabled="false" />  
  42.   
  43.         <activity  
  44.             android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"  
  45.             android:enabled="false"  
  46.             android:icon="@drawable/__leak_canary_icon"  
  47.             android:label="@string/__leak_canary_display_activity_label"  
  48.             android:taskAffinity="com.squareup.leakcanary"  
  49.             android:theme="@style/__LeakCanary.Base" >  
  50.             <intent-filter>  
  51.                 <action android:name="android.intent.action.MAIN" />  
  52.   
  53.                 <category android:name="android.intent.category.LAUNCHER" />  
  54.             </intent-filter>  
  55.         </activity>  
  56.     </application>  
  57.   
  58. </manifest>  


如上所示LeakCanary给我们自动添加了两个Service和一个Activity,并添加了对SD卡的读写权限


It 's so simple.

注: 

1、如果在Release模式下请使用RefWatcher.DISABLED

 2、在Activity或Fragment 的 Destroy方法中添加检测(很好理解,就是判断一个Activity或Fragment想要被销毁的时候,是否还有其他对象持有其引用导致Activity或Fragment不能被回收,从而导致内存泄露)


源码地址:https://github.com/mickyliu945/LeakCanarySample   ​​点击打开链接​

作者: ​​一点点征服​

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利