1. 程式人生 > >Android實戰——LeakCanary檢測記憶體洩漏

Android實戰——LeakCanary檢測記憶體洩漏

LeakCanary檢測記憶體洩漏

前言

記憶體洩漏對於初學者們可能是一個陌生的詞語,但是卻頻頻發生於自己的軟體上,只不過自己不知道而已。同理,記憶體溢位也是一個道理。而記憶體洩漏和記憶體溢位常常是面試的考題,所以早點掌握是必不可少的

記憶體洩漏的簡介

記憶體洩漏是指:物件在它有限的生命週期結束時,它們將被垃圾回收,如果在回收時,這個物件還被一系列的引用,導致該物件不會被回收,那麼就會導致記憶體洩漏。隨著洩漏的累積,應用將消耗完記憶體,應用的流暢性就會大大減弱

常見的記憶體洩漏有:

  1. 靜態變數引用導致記憶體洩漏
  2. 屬性動畫未及時關閉導致的記憶體洩漏

記憶體溢位的簡介

涉及到記憶體洩漏,當然也逃不過記憶體溢位的內容

記憶體溢位是指:程式要求的記憶體,超出了系統所能分配的範圍,從而發生溢位。Android應用程式的預設最大記憶體值為16M,如果你使用的記憶體超過最大值,則會導致應用報錯

常見的記憶體溢位有:

  1. 圖片過大導致記憶體溢位

LeakCanary的配置與使用

LeakCanary是square公司開發出來的檢測記憶體洩漏的神器,他可以嵌入到我們的應用中,幫助我們自動檢測記憶體洩漏

一、新增依賴

在專案的gradle中新增對LeakCanary的依賴

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' }

二、LeakCanary的使用

首先,需要建立一個類繼承自Application,為了讓我們LeakCanary在全域性的Activity中能夠起作用

public class BaseApplication extends Application {
    @Override
    public
void onCreate() { super.onCreate(); } }

接著,在Manifests檔案中指定該Application

<application
    android:name=".LeakCanary.BaseApplication">
</application>

最後,就是在Application中直接配置我們的LeakCanary

public class BaseApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //配置LeakCanary
        setupLeakCanary();
    }

    /**
     * 配置LeakCanary
     */
    private void setupLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return;
        }
        LeakCanary.install(this);
    }
}

到此我們的LeakCanary就已經嵌入成功,就剩測試了

三、測試記憶體洩漏

我們採用靜態變數的記憶體洩漏來作為我們的測試結果,建立一個類,該類的作用可以儲存一個Activity物件到一個ArrayList中,讓Activity一直存在

public class ActivityPool {

    public static ActivityPool activityPool = new ActivityPool();
    public static ArrayList<Activity> activities = new ArrayList<>();

    public static ActivityPool getActivity() {
        return activityPool;
    }

    public static void addActivity(Activity activity) {
        activities.add(activity);
    }
}

做好了記憶體洩漏類之後,就在我們的主介面中直接使用該類,並將主介面的Activity存放在ArrayList中

public class LeakCanaryActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leakcanary);

        ActivityPool.getActivity().addActivity(this);
    }
}

這個時候,我們就已經模擬了記憶體洩漏了,接著,就可以執行程式進行測試了

四、測試結果與分析

我們執行程式進入主介面,那麼主介面的Activity就被儲存起來了,這個時候是沒什麼事情的,因為主介面的Activity還被引用,並不會發生記憶體洩漏。接著,我們退出主介面,按道理是:退出主介面Activity,其生命週期就被結束了,該Activity必須被系統回收,但是我們還留了一手,將它儲存起來了,那麼等待一段時間後,就會在通知欄收到LeakCanary的通知資訊

這個時候,記憶體洩漏報告就出來了,點選通知資訊,進入記憶體洩漏報告分析

結果分析得:

第一部分(ActivityPool類的activities變數)由於第二部分(ArrayList中的某個陣列)和第三部分(陣列中的某個物件) 導致第四部分(LeakCanaryActivity類的例項instance)洩露

這樣我們就可以很容易的定位到記憶體洩漏的部分

上面說到為什麼要在關閉Activity時,等待一段時間才會出現記憶體洩漏報告呢?

原因是:LeakCanary會監聽所有Activity的生命週期,並且在Activity的onDestory函式結束後,將該Activity新增到記憶體洩漏監控佇列中。接著,在後臺執行緒中檢測這個引用是否被清除,如果沒有將會發生GC操作(垃圾回收),如果引用仍然沒有清除,將heap記憶體dump到一個.hprof檔案並存放在手機系統裡,應用會開啟另一個程序來分析該.hprof檔案,最後匯出洩漏引用鏈,傳回應用程式中,通過推送推送出資訊

結語

LeakCanary的使用並不難,重要的是如何排除記憶體洩漏的問題,可能大部分問題還是需要在實戰中才能摸索出來,這裡只是舉一例子,不過通過這篇之後,相信你對記憶體洩漏和溢位都有一個大概的瞭解,對待類似面試題應該是沒什麼問題了