Android內存泄露自動檢測神器LeakCanary


經典的面試題:

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秒左右顯示)



b、通知顯示



c、桌面自動添加的圖表



d、內存泄露列表



e、內存泄露詳細



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   點擊打開鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM