使用LeakCanary遇到的問題 就是不彈出來


今天樓主遇到引用LeakCanary時代碼跟官網一樣但是就不彈出來。樓主新建項目就可以正常使用。樓主郁悶半天,現在終於整出來了。

樓主主工程app引用module為thirdParty,本想為了整潔三方的都扔進這個thirdParty 結果導致了這個沒弄出來。

1.寫一個application :

  1. <application  
  2.        android:name=".BaseApplication"  


  1. public class BaseApplication extends Application {  
  2.     private static BaseApplication app;  
  3.     private DaoMaster daoMaster;  
  4.     private DaoSession daoSession;  
  5.     private SQLiteDatabase db;  
  6.     private String TAG="BaseApplication";  
  7.   
  8.     @Override  
  9.     public void onCreate() {  
  10.         super.onCreate();  
  11.         Log.i(TAG, "onCreate: ");  
  12.         app = this;  
  13.   
  14.         LeakCanary.install(this);  
  15.         initDB();  
  16.     }  

2.寫一段讓程序泄露的代碼:

  1. void startAsyncTask() {  
  2.   
  3.        // This async task is an anonymous class and therefore has a hidden reference to the outer  
  4.        // class MainActivity. If the activity gets destroyed before the task finishes (e.g. rotation),  
  5.        // the activity instance will leak.  
  6.        new AsyncTask<Void, Void, Void>() {  
  7.            @Override  
  8.            protected Void doInBackground(Void... params) {  
  9.                // Do some slow work in background  
  10.                SystemClock.sleep(200000);  
  11.                return null;  
  12.            }  
  13.        }.execute();  
  14.        Toast.makeText(this, "請關閉這個A完成泄露", Toast.LENGTH_SHORT).show();  
  15.    }  


3.添加build.gradle 由於我把所有的依賴都寫在的thirdParty這個lib中

仔細觀察一下這個引用不太一樣:

我們平時引用都是:

  1. compile 'com.github.lzyzsd.randomcolor:library:1.0.0'  

而LeakCanary的引用是:

  1. debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'  

 

后來我又寫到了主app中 結果可以使用了。。。

查了一下他們的含義:

Compile

compile是對所有的build type以及favlors都會參與編譯並且打包到最終的apk文件中。

Provided

Provided是對所有的build type以及favlors只在編譯時使用,類似eclipse中的external-libs,只參與編譯,不打包到最終apk。

APK

只會打包到apk文件中,而不參與編譯,所以不能再代碼中直接調用jar中的類或方法,否則在編譯時會報錯

Test compile

Test compile 僅僅是針對單元測試代碼的編譯編譯以及最終打包測試apk時有效,而對正常的debug或者release apk包不起作用。

Debug compile

Debug compile 僅僅針對debug模式的編譯和最終的debug apk打包。

Release compile

Release compile 僅僅針對Release 模式的編譯和最終的Release apk打包。

還不太清楚為啥。。。但是給大家提個醒。

下面轉一個非常好的文章:http://droidyue.com/blog/2016/03/28/android-leakcanary/

懶人可以看我下面的轉載

 

Android內存泄漏檢測利器:LeakCanary

MAR 28TH, 2016

是什么?

一言以蔽之:LeakCanary是一個傻瓜化並且可視化的內存泄露分析工具

為什么需要LeakCanary?

因為它簡單,易於發現問題,人人可參與。

  • 簡單:只需設置一段代碼即可,打開應用運行一下就能夠發現內存泄露。而MAT分析需要Heap Dump,獲取文件,手動分析等多個步驟。
  • 易於發現問題:在手機端即可查看問題即引用關系,而MAT則需要你分析,找到Path To GC Roots等關系。
  • 人人可參與:開發人員,測試測試,產品經理基本上只要會用App就有可能發現問題。而傳統的MAT方式,只有部分開發者才有精力和能力實施。

如何集成

盡量在app下的build.gradle中加入以下依賴

1
2
3 4 5 
 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  }

在Application中加入類似如下的代碼

1
2
3 4 5 6 7 
public class ExampleApplication extends Application {   @Override public void onCreate() {  super.onCreate();  LeakCanary.install(this);  } } 

到這里你就可以檢測到Activity的內容泄露了。其實現原理是設置Application的ActivityLifecycleCallbacks方法監控所有Activity的生命周期回調。內部實現代碼為

1
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 
public final class ActivityRefWatcher {  private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {  public void onActivityCreated(Activity activity, Bundle savedInstanceState) {  }   public void onActivityStarted(Activity activity) {  }   public void onActivityResumed(Activity activity) {  }   public void onActivityPaused(Activity activity) {  }   public void onActivityStopped(Activity activity) {  }   public void onActivitySaveInstanceState(Activity activity, Bundle outState) {  }   public void onActivityDestroyed(Activity activity) {  ActivityRefWatcher.this.onActivityDestroyed(activity);  }  };  private final Application application;  private final RefWatcher refWatcher;   public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {  if(VERSION.SDK_INT >= 14) {  ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);  activityRefWatcher.watchActivities();  }  } .... } 

想要檢測更多?

首先我們需要獲得一個RefWatcher,用來后續監控可能發生泄漏的對象

1
2
3 4 5 6 7 8 9 10 11 12 13 14 
public class MyApplication extends Application {  private static RefWatcher sRefWatcher;    @Override  public void onCreate() {  super.onCreate();  sRefWatcher = LeakCanary.install(this);  }   public static RefWatcher getRefWatcher() {  return sRefWatcher;  } } 

監控某個可能存在內存泄露的對象

1
MyApplication.getRefWatcher().watch(sLeaky); 

哪些需要進行監控

默認情況下,是對Activity進行了檢測。另一個需要監控的重要對象就是Fragment實例。因為它和Activity實例一樣可能持有大量的視圖以及視圖需要的資源(比如Bitmap)即在Fragment onDestroy方法中加入如下實現

1
2
3 4 5 6 7 
public class MainFragment extends Fragment {  @Override  public void onDestroy() {  super.onDestroy();  MyApplication.getRefWatcher().watch(this);  } } 

其他也可以監控的對象

  • BroadcastReceiver
  • Service
  • 其他有生命周期的對象
  • 直接間接持有大內存占用的對象(即Retained Heap值比較大的對象)

何時進行監控

首先,我們需要明確什么是內存泄露,簡而言之,某個對象在該釋放的時候由於被其他對象持有沒有被釋放,因而造成了內存泄露。

因此,我們監控也需要設置在對象(很快)被釋放的時候,如Activity和Fragment的onDestroy方法。

一個錯誤示例,比如監控一個Activity,放在onCreate就會大錯特錯了,那么你每次都會收到Activity的泄露通知。

如何解決

常用的解決方法思路如下

  • 盡量使用Application的Context而不是Activity的
  • 使用弱引用或者軟引用
  • 手動設置null,解除引用關系
  • 將內部類設置為static,不隱式持有外部的實例
  • 注冊與反注冊成對出現,在對象合適的生命周期進行反注冊操作。
  • 如果沒有修改的權限,比如系統或者第三方SDK,可以使用反射進行解決持有關系

加入例外

有些特殊情況,我們需要忽略一些問題,這時候就需要添加例外規則。比如ExampleClass.exampleField會導致內存泄漏,我們想要忽略,如下操作即可。

1
2
3 4 5 6 7 8 9 
// ExampleApplication is defined in "Customizing and using the no-op dependency" 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);  } } 

如何實現的

LeakCanary實際上就是在本機上自動做了Heap dump,然后對生成的hprof文件分析,進行結果展示。和手工進行MAT分析步驟基本一致。

如何不影響對外版APK

是的,這個問題確實值得關注,因為LeakCanary確實是影響程序運行的,尤其是heap dump操作,不過好在這件事Square已經考慮了,即在我們增加依賴時

1
2
3 
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 

其中releaseCompile和testCompile這兩個的依賴明顯不同於debugCompile的依賴。它們的依賴屬於NOOP操作。

NOOP,即No Operation Performed,無操作指令。常用的編譯器技術會檢測無操作指令並出於優化的目的將無操作指令剔除。

因而,只要配置好releaseCompile和testCompile的依賴,就無需擔心對外版本的性能問題了。

實踐中的問題

  • 如果targetSdkVersion為23,在6.0的機器上會存在問題,卡死,因為LeakCanary並沒有很好支持Marshmallow運行時權限,所以始終得不到sd卡權限,進而導致卡死。

注意

  • 目前LeakCanary一次只能報一個泄漏問題,如果存在內存泄漏但不是你的模塊,並不能說明這個模塊沒有問題。建議建議將非本模塊的泄漏解決之后,再進行檢測。

Anroid中內存泄漏相關文章


免責聲明!

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



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