1. 程式人生 > >LeakCanary的使用和實現原理

LeakCanary的使用和實現原理

  • Android 應用記憶體洩漏問題,一直是效能優化的重點。在不清楚記憶體洩漏的大致範圍時,通過人為測試模擬重現或無目的地分析 heap dump等方法來檢測,都太繁瑣、耗時且定位不準。

    什麼是記憶體洩漏?

    在 Java 世界中,一切物件都有生命週期,如同人的壽命。人死燈滅,入輪迴,轉世投胎。Java 物件的生命週期結束後,將被 GC 回收,原先佔用的記憶體會有新的用途。但凡是總有例外,就如孫悟空可以修改生死譜長生不死,聶小倩能殘存人間人鬼相戀。Java 物件有時也會”長死不死“,GC 拿它沒有辦法,這種情況就是記憶體洩漏。造成這種情況的原因是:Java 物件被另一個生命週期更長物件持有,具有 可達性

    ,這並不是我們想要的。

    問:有沒有一種簡單直接且能有效定位記憶體洩漏位置的方法呢?

    :有,那就是 LeakCanary 。我們可以簡單地人為:將一個 App 作為輸入,通過 LeakCanary 檢測後,就會得到記憶體洩漏位置結果(如果存在的話)。

    LeakCanary

    知其然知其所以然LeakCanary 如此強大實用,那麼:LeakCanary 是怎麼實現的?

  • Android 應用的整個生命週期由其元件的生命週期組成,如下圖中所示。使用者使用應用的過程中,在不同介面之間跳轉,每個介面都經歷著”生死“的轉換,可在此建立檢測點。Activity/Fragment
    都有 onDestory() 回撥方法, 進入此方法後,Activity/Fragment生命週期結束,應該被回收。
  • 簡述宣告週期

  • 然後我們需要解決:如何得到未被回收的物件。ReferenceQueue+WeakReference+手動呼叫 GC可實現這個需求。

    WeakReference 建立時,傳入一個 ReferenceQueue 物件。當被 WeakReference 引用的物件的生命週期結束,一旦被 GC 檢查到,GC 將會把該物件新增到 ReferenceQueue 中,待ReferenceQueue處理。當 GC 過後物件一直不被加入 ReferenceQueue,它可能存在記憶體洩漏。

  • 獲得未被回收的 Object

  • 找到了未被回收的物件,如何確認是否真的記憶體洩漏?這裡可以將問題轉換為:未被回收的物件,是否被其他物件引用?找出其最短引用鏈。VMDebug + HAHA 完成需求。

    VM 會有堆內各個物件的引用情況,並能以hprof檔案匯出。HAHA 是一個由 square 開源的 Android 堆分析庫,分析 hprof 檔案生成Snapshot物件。Snapshot用以查詢物件的最短引用鏈。

  • 解析hprof

  • 找到最短引用鏈後,定位問題,排查程式碼將會事半功倍。
  • 如下泳道圖分析, LeakCanary 各個模組如何配合達到檢測目的。

    泳道圖