效能優化——記憶體洩漏(2)工具分析篇

GitLqr發表於2017-06-30

記憶體洩漏系列文章:
效能優化——記憶體洩漏(1)入門篇
效能優化——記憶體洩漏(2)工具分析篇
效能優化——記憶體洩漏(3)程式碼分析篇

一、簡述

在上一篇《效能優化——記憶體洩漏(1)入門篇》中,介紹了記憶體洩漏的基本概念,並舉了一個Demo,結合簡單的程式碼分析,猜測出Demo中存在記憶體洩漏,並用Android Studio自帶的Memory Monitor證明了我們的猜測,但開發中,業務邏輯可能比較複雜,物件引用繁多,難道都要這樣去做程式碼分析嗎?肯定不行,程式設計師的精力有限,且“很懶”(追求效率),我們需要工具來幫助我們進行分析。下面就來看看都有什麼神器吧。

二、工具分析

1、System Information

System Information是Android Studio自帶的分析工具,可以通過它來判斷APP整體是否存在記憶體洩漏。

一個不存在記憶體洩漏的APP,在其退出並執行過GC後,APP中所有的View和Activity都會被銷燬,所以,我們可以根據退出後記憶體中View和Activity的數量來判斷這個APP是否存在記憶體洩漏。操作如下:

以上一篇中的Demo為例:
執行APP-->開啟一個Activity-->螢幕旋轉-->點返回鍵(兩次)直到到桌面-->執行GC-->System Information-->Memory Usage

通過上述操作,會生成一個txt文字,其中就記錄著View和Activity的數量。如下圖所示,它們的值都為0(主要看Activities),說明本APP不存在記憶體洩漏。相反的,只要值不為0,那麼APP是存在記憶體洩漏的。

這種方式只能判斷整個APP是否存在記憶體洩漏,但無法知道哪裡有記憶體洩漏,也無法得知是哪些物件引用造成的記憶體洩漏。

2、Analyzer Tasks

Analyzer Tasks 是Android Studio自帶的分析工具,可以幫助我們快速定位記憶體洩漏,而且使用上 very easy~

開啟一個記憶體快照(.hprof檔案),Android Studio的右側會出現Analyzer Tasks。

開啟Analyzer Tasks後,可以發現有2個選項和一個按鈕,說明如下圖所示,我們需要的就是第一個"Detect Leaked Activities"。

執行任務後,下方的Analysis Results中會得到洩漏的Activity,而且直接定位到了MemoryLeakActivity[0],要上篇中得到的結果一樣。

3、MemoryAnalyzer(MAT)

這工具,真心覺得有點複雜,但功能比Android Studio自帶的Analyzer Tasks要強大的多。

MemoryAnalyzer是基於eclipse開發的,是一個單獨的軟體,它也是對.hprof檔案進行分析,但必須是標準的.hprof檔案,可以從Android Studio中匯出。

執行MAT,通過File-->Open Dump分別開啟剛剛匯出的test1.hprof和test2.hprof,選擇Leak Suspects Report-->Finish。

分析的方式有兩種,一種是單檔案分析,一種是多檔案分析,我們先進行單檔案分析。

1)單檔案分析

切換到test2.hprof,開啟Histogram。

點選Histogram後,會出來一個Histogram標籤,會列出APP中所有類的例項個數,感覺跟Android Studio的.hprof檢視器差不多,MAT中的Objects相當於AS中檢視器的Total Count。

通過包名篩選,找出了我們自己寫的程式碼,Android Studio的話可以通過切換檢視來定位。可以發現MemoryLeakActivity的例項有2個,說明它可能存在洩漏,再聯絡之前在獲取快照之前執行過GC,而這個Activity還沒有銷燬,說明這個Activity應該是洩漏了。好,到這裡單檔案分析就結束了。

2)多檔案分析

分別將test1.hprof和test2.hprof的histogram新增到Compare Basket,詳細操作如下圖所示。

在Compare Basket中會有剛剛新增的兩個.hprof,點選紅色感嘆號進行對比。

出來的Compared Tables列表跟Histogram很像,不過Objects和Shallow Heap標籤都是成雙成對。

一樣,我們只關心我們自己的程式碼,所以通過Regex進行篩選。通過資料分析,可以知道,在旋轉螢幕前後,MemoryLeakActivity的例項由1增加到了2,又因為test2.hprof是在執行了GC後獲取的,所以可以判定MemoryLeakActivity在旋轉螢幕後,記憶體洩漏了。

3)引用跟蹤

通過單檔案分析或多檔案分析,我們知道MemoryLeakActivity發生了記憶體洩漏(被別的例項引用導致無法被GC回收),所以回到test2.hporf的Histogram,篩選出MemoryLeakActivity,右擊List objects-->with incoming references。

出來的結果有2大塊,即對記憶體中的2個MemoryLeakActivity例項分別被引用的結果進行了分類,可以看到每個MemoryLeakActivity都被好多個物件引用了。

結合上篇中提到的java中幾個特殊類,我們知道SoftReference、WeakReference和PhantomReference在GC一般不會造成記憶體洩漏,所以這些我們可以不管,也說是說,我們可以對它們進行排除。

對兩個Activity分別排除軟、弱、虛引用後,得到的結果分別如下:

簡單分析下就知道了,第一個MemoryLeakActivity例項是洩漏的,引用它的物件就是CommonUtil。

三、總結

1、工具方面

個人還是比較推薦使用Android Studio整合的System Information和Analyzer Tasks,主要是使用上方便快捷,還很簡單,如果你是高手,並且需要有更強大的功能來幫助你檢查APP中的記憶體洩漏的話,建議使用MAT,在網上多找些比較詳細的文章看看,本文對MAT的介紹只是冰山一角。

2、操作方面

工具僅僅只是幫助我們快速定位APP中的記憶體洩漏,並不能直接告訴我們哪裡有記憶體洩漏,實際開發中,需要我們去猜測,去思考,要有清晰的思維,想方設法的構思記憶體洩漏的判定依據。這需要我們自己去摸索,積累一定的經驗。最後,在獲取記憶體快照(Dump Java Heap)之前,建議多點幾次Initiate GC,等記憶體穩定成一條線時再獲取記憶體快照。

相關文章