Android 檢測內存泄漏,必須使用方便強大到滅絕人性的 leakcanary。javascript
leakcanary 是 square 公司開發的,square 擁有衆多強大的 Android 開源項目,如,OkHttp、retrofit、otto、picasso,簡直撐起了Android 開發的半邊天。java
一行代碼就能夠捕找到已經泄漏的內存泄漏,而且顯示出出現內存泄漏的變量或線程、泄漏時的引用路徑和出現泄漏的地方。android
1.添加依賴git
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}複製代碼
2.初始化 leakcanarygithub
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
}
}複製代碼
寫一段內存泄露的代碼。app
MainActivity.javaide
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
test();
finish();
startActivity(new Intent(MainActivity.this, Main2Activity.class));
}
// 這裏會發生內存泄漏
public void test() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}複製代碼
MainActivity 中點擊按鈕後,'test()' 方法內部匿名內部類執行了耗時任務,而且同時 finish()
掉 MainActivity,可是此匿名內部類依然在運行任務,而且隱式的持有 MainActivity 引用,致使 MainActivity 不能及時被 GC 回收,致使內存泄露。this
LeakCanary 檢測出內存泄露後,會在狀態欄顯示一條通知,點進去就能夠看到詳細信息。以下圖:spa
含義:線程
標題欄顯示內存泄露的類和泄露的內存大小,菜單欄提供分享出更詳細的信息,包括堆棧信息或者 .hprof
文件。藍色欄顯示包名,第一行顯示出現泄露的線程,下面幾行顯示全部的引用,最後一行顯示泄露的類。
MainActivity$1.this$0
的含義:
符號 「$」 表明後者是前者的內部類,「.」就是對象調用方法那個點。
用 「.」 分爲兩部分,前面總體表明 MainActivity 的一個匿名內部類,用 1 表示,在這裏表明 Runnable 匿名類,後面部分 this$0
總體表明外部類。
看到這個內存泄露信息,首先定位到 MainActivity 中,同時能夠看得出是 MainActivity 的實例出現的內存泄露,而且發生在子線程中,看到代碼,咱們就能夠確認確定是在 Runnale 匿名內部類中隱式的引用了 MainActivity 致使的內存泄露。
在這裏打一個斷點:
能夠看到匿名類內部存在一個外部 MainActivity 的引用。
找到緣由就好辦了,靜態化匿名內部類就解決問題了:
// 靜態
public static void test() {
// ...
}複製代碼
靜態化以後,發現該匿名內部類中不在持有外部類 MainActivity 對引用,也就不會在 MainActivity 銷燬後,出現內存泄露了。
本文由 Bakumon 創做,採用 知識共享署名4.0 國際許可協議進行許可本站文章除註明轉載/出處外,均爲本站原創或翻譯,轉載前請務必署名