Android內存優化8 內存檢測工具2 LeakCanary——直白的展現Android中的內存泄露
之前碰到的OOM問題,終於很直白的呈現在我的眼前:我嘗試了MAT,但是發現不怎麽會用。直到今天終於發現了這個新工具:
當我們的App中存在內存泄露時會在通知欄彈出通知:
當點擊該通知時,會跳轉到具體的頁面,展示出Leak的引用路徑,如下圖所示:
LeakCanary 可以用更加直白的方式將內存泄露展現在我們的面前。
以下是我找到的學習資料,寫的非常棒:
1、LeakCanary: 讓內存泄露無所遁形
2、LeakCanary 中文使用說明
AndroidStudio (官方)上使用LeakCanary 請移步:
https://github.com/square/leakcanary
Eclipse
https://github.com/SOFTPOWER1991/LeakcanarySample-Eclipse
Android studio (自己弄的)上使用LeakCanary也可以看這個:
leakcanarySample_androidStudio
工程包括:
- LeakCanary庫代碼
- LeakCanaryDemo示例代碼
使用步驟:
-
將LeakCanary import 入自己的工程
-
添加依賴:
compile project(‘:leakcanary‘)
-
在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); ...... } ..... }
-
在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();
}
}
- 在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- 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".
- 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
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.micky.leakcanarysamples"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="10"
- android:targetSdkVersion="23" />
- <!-- To store the heap dumps and leak analysis results. -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <application
- android:name="com.micky.leakcanarysamples.BaseApplication"
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.micky.leakcanarysamples.MainActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="com.micky.leakcanarysamples.TestActivity" />
- <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>
- </application>
- </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中的內存泄露