1. 程式人生 > >Android內存優化8 內存檢測工具2 LeakCanary——直白的展現Android中的內存泄露

Android內存優化8 內存檢測工具2 LeakCanary——直白的展現Android中的內存泄露

release title ngs rotation text this outer android中 class

之前碰到的OOM問題,終於很直白的呈現在我的眼前:我嘗試了MAT,但是發現不怎麽會用。直到今天終於發現了這個新工具:

當我們的App中存在內存泄露時會在通知欄彈出通知:

技術分享圖片

當點擊該通知時,會跳轉到具體的頁面,展示出Leak的引用路徑,如下圖所示:

技術分享圖片

LeakCanary 可以用更加直白的方式將內存泄露展現在我們的面前。

以下是我找到的學習資料,寫的非常棒:
1、LeakCanary: 讓內存泄露無所遁形
2、LeakCanary 中文使用說明

AndroidStudio (官方)上使用LeakCanary 請移步:
https://github.com/square/leakcanary

Eclipse

上使用LeakCanary 請移步我的:
https://github.com/SOFTPOWER1991/LeakcanarySample-Eclipse

Android studio (自己弄的)上使用LeakCanary也可以看這個:

leakcanarySample_androidStudio

工程包括:

  1. LeakCanary庫代碼
  2. LeakCanaryDemo示例代碼

使用步驟:

  1. 將LeakCanary import 入自己的工程

  2. 添加依賴:

    compile project(‘:leakcanary‘)

  3. 在Application中進行配置

    public class ExampleApplication extends Application {
    
      ......
      //在自己的Application中添加如下代碼
    public static RefWatcher getRefWatcher(Context context) {
        ExampleApplication application = (ExampleApplication) context
                .getApplicationContext();
        return application.refWatcher;
    }
    
      //在自己的Application中添加如下代碼
    private RefWatcher refWatcher;
    
    @Override
    public void onCreate() {
        super.onCreate();
        ......
            //在自己的Application中添加如下代碼
        refWatcher = LeakCanary.install(this);
        ......
    }
    
    .....
    }
    
  4. 在Activity中進行配置

public class MainActivity extends AppCompatActivity {

    ......
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
            //在自己的應用初始Activity中加入如下兩行代碼
        RefWatcher refWatcher = ExampleApplication.getRefWatcher(this);
        refWatcher.watch(this);

        textView = (TextView) findViewById(R.id.tv);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startAsyncTask();
            }
        });

    }

    private void async() {

        startAsyncTask();
    }

    private void startAsyncTask() {
        // This async task is an anonymous class and therefore has a hidden reference to the outer
        // class MainActivity. If the activity gets destroyed before the task finishes (e.g. rotation),
        // the activity instance will leak.
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                // Do some slow work in background
                SystemClock.sleep(20000);
                return null;
            }
        }.execute();
    }


}

  1. 在AndroidMainfest.xml 中進行配置,添加如下代碼
        <service
            android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"
            android:enabled="false"
            android:process=":leakcanary" />
        <service
            android:name="com.squareup.leakcanary.DisplayLeakService"
            android:enabled="false" />

        <activity
            android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
            android:enabled="false"
            android:icon="@drawable/__leak_canary_icon"
            android:label="@string/__leak_canary_display_activity_label"
            android:taskAffinity="com.squareup.leakcanary"
            android:theme="@style/__LeakCanary.Base" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

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. <uses-sdk
  7. android:minSdkVersion="10"
  8. android:targetSdkVersion="23" />
  9. <!-- To store the heap dumps and leak analysis results. -->
  10. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  11. <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  12. <application
  13. android:name="com.micky.leakcanarysamples.BaseApplication"
  14. android:allowBackup="true"
  15. android:icon="@mipmap/ic_launcher"
  16. android:label="@string/app_name"
  17. android:supportsRtl="true"
  18. android:theme="@style/AppTheme" >
  19. <activity
  20. android:name="com.micky.leakcanarysamples.MainActivity"
  21. android:label="@string/app_name"
  22. android:theme="@style/AppTheme.NoActionBar" >
  23. <intent-filter>
  24. <action android:name="android.intent.action.MAIN" />
  25. <category android:name="android.intent.category.LAUNCHER" />
  26. </intent-filter>
  27. </activity>
  28. <activity android:name="com.micky.leakcanarysamples.TestActivity" />
  29. <service
  30. android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"
  31. android:enabled="false"
  32. android:process=":leakcanary" />
  33. <service
  34. android:name="com.squareup.leakcanary.DisplayLeakService"
  35. android:enabled="false" />
  36. <activity
  37. android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
  38. android:enabled="false"
  39. android:icon="@drawable/__leak_canary_icon"
  40. android:label="@string/__leak_canary_display_activity_label"
  41. android:taskAffinity="com.squareup.leakcanary"
  42. android:theme="@style/__LeakCanary.Base" >
  43. <intent-filter>
  44. <action android:name="android.intent.action.MAIN" />
  45. <category android:name="android.intent.category.LAUNCHER" />
  46. </intent-filter>
  47. </activity>
  48. </application>
  49. </manifest>

如上所示LeakCanary給我們自動添加了兩個Service和一個Activity,並添加了對SD卡的讀寫權限






It ‘s so simple.

註:

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

2、在Activity或Fragment 的 Destroy方法中添加檢測(很好理解,就是判斷一個Activity或Fragment想要被銷毀的時候,是否還有其他對象持有其引用導致Activity或Fragment不能被回收,從而導致內存泄露)

Android內存優化8 內存檢測工具2 LeakCanary——直白的展現Android中的內存泄露