經典的面試題:
a、怎樣在coding過程中避免內存泄露?
b、怎樣檢測內存泄露?
這兩個問題我想大部分Android 職位面試時都會被問到吧。
怎樣避免就不贅述了,網上很多答案。
工具呢,當然也有很多,比如DDMS、MAT等,但是怎樣在我們編碼過程中植入內存檢測代碼,讓我們程序在開發調試階段就能發現內存泄露呢?好了,現在該大名鼎鼎的LeakCanary出場了,它是Square公司的一個內存探測開源項目。下面就介紹下怎樣使用.
1、配置gradle依賴:
- debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
- releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
2、初始化Watcher
- package com.micky.leakcanarysamples;;
- import android.app.Application;
- import com.squareup.leakcanary.LeakCanary;
- import com.squareup.leakcanary.RefWatcher;
- /**
- * @Project LeakCanaryTest
- * @Packate com.micky.leakcanarysamples;
- * @Description
- * @Author Micky Liu
- * @Email mickyliu@126.com
- * @Date 2016-01-04 10:32
- * @Version 1.0
- */
- public class BaseApplication extends Application {
- private static BaseApplication instance;
- private RefWatcher mRefWatcher;
- @Override
- public void onCreate() {
- super.onCreate();
- instance = this;
- mRefWatcher = Constants.DEBUG ? LeakCanary.install(this) : RefWatcher.DISABLED;
- }
- public static BaseApplication getInstance() {
- return instance;
- }
- public static RefWatcher getRefWatcher() {
- return getInstance().mRefWatcher;
- }
- }
3、在Activity或Fragment中添加檢測
- package com.micky.leakcanarysamples;
- import android.app.Activity;
- import android.support.v7.app.AppCompatActivity;
- /**
- * @Project LeakCanaryTest
- * @Packate com.micky.leakcanarysamples;
- * @Description
- * @Author Micky Liu
- * @Email mickyliu@126.com
- * @Date 2016-01-04 10:39
- * @Version 1.0
- */
- public class BaseActivity extends AppCompatActivity {
- @Override
- protected void onDestroy() {
- super.onDestroy();
- BaseApplication.getRefWatcher().watch(this);
- }
- }
4、測試
- package com.micky.leakcanarysamples;;
- import android.os.Bundle;
- import android.os.Handler;
- /**
- * @Project LeakCanaryTest
- * @Packate com.micky.leakcanarysamples;
- * @Description
- * @Author Micky Liu
- * @Email mickyliu@126.com
- * @Date 2016-01-04 10:29
- * @Version 1.0
- */
- public class TestActivity extends BaseActivity {
- private final Handler mHandler = new Handler();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //模擬內存泄露
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- }
- }, 3 * 60 * 1000);
- finish();
- }
- }
5、測試結果
a、Toast顯示(大概10秒左右顯示)
b、通知顯示
c、桌面自動添加的圖表
d、內存泄露列表
e、內存泄露詳細
LogCat可以看到日志日下(hprof文件可以用MAT打開進行分析):
- 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卡的讀寫權限
注:
1、如果在Release模式下請使用RefWatcher.DISABLED
2、在Activity或Fragment 的 Destroy方法中添加檢測(很好理解,就是判斷一個Activity或Fragment想要被銷毀的時候,是否還有其他對象持有其引用導致Activity或Fragment不能被回收,從而導致內存泄露)
源碼地址:https://github.com/mickyliu945/LeakCanarySample 點擊打開鏈接