1. 程式人生 > >效能優化之記憶體洩露(Memory Leak)解決

效能優化之記憶體洩露(Memory Leak)解決

1 分析記憶體洩漏遇到的問題

(1)把兩個dump檔案對比,找出GC root樹,發現MainActivity例項被CommonUtil引用,說懷疑此處可能有洩露。但實際開發的時候,很多這種情況,莫非都要懷疑一遍?我們必然知道mat只是個工具,提供洩露的建議,但工具能提供給碼農最關鍵的建議難道就到這裡為止了嗎?
(2)在mat分析工具的時候,沒有結合旋轉螢幕導致Activity洩露的例子分析,把大把的時間用在了分析工具的使用,並沒能從這個mat工具分析出旋轉螢幕如何導致了Activity洩露?

2 如何找到專案中存在的記憶體洩露

2.1 Android Monitors memory(最常用方法,可定位具體洩漏)

2.1.1 Android Monitors(監控)的記憶體分析

(1)備註:Android Studio將Heap Viewer(堆檢視)整合到Android Monitors,即是:只要分析Android Monitors即可,如圖。
(2)分析:那麼如何檢測呢?Heap Viewer中的數值會自動在每次發生GC時會自動更新,那麼我們是等著他自己GC麼?既然我們是來看記憶體洩漏,那麼我們在需要檢測記憶體洩漏的用例執行過後手動GC下,然後觀察data object一欄的total size(也可以觀察Heap Size/Allocated記憶體的情況,尤其是Allocated記憶體),看看記憶體是不是會回到一個穩定值。多次操作後只要記憶體是穩定在某個值,那麼說明沒有記憶體溢位的;如果發現記憶體在每次GC後,記憶體都在增長,不管是慢增長還是快速增長,都說明有記憶體洩漏的可能性。
(3)直觀:最直觀的看分配記憶體增長情況,知道該動作是否發生記憶體洩露。動作發生之前:GC完後分配記憶體1.4M; 動作發生之後:GC完後分配記憶體1.6M。


(4)結果:那麼這裡就已經初步判斷這個操作導致了記憶體洩露的情況。

2.1.2 Heap Snapshot堆快照分析

檢視堆的引用情況判斷是否有記憶體洩漏:當你點選某個物件時,將展開該物件內部含有哪些物件,同時C區域也會顯示哪些物件引用了該物件。 某物件引用物件,在這裡面能看出其沒誰引用了,比如在記憶體洩漏中,可以看出來它被誰引用,如下圖:
這裡寫圖片描述

2.2 使用MAT記憶體分析工具找懷疑物件

2.2.1 MAT使用

2.2.2 MAT對比

MAT對比操作前後的hprof來定位記憶體洩露是洩露了什麼資料物件。(這樣做可以排除一些物件,不用後面去檢視所有被引用的物件是否是嫌疑)。快速定位到操作前後所持有的物件哪些是增加了(GC後還是比之前多出來的物件就可能是洩露物件嫌疑犯)。如圖的3個步驟將前後的快照新增到對比欄中對比。
這裡寫圖片描述


這裡寫圖片描述
這裡寫圖片描述
另外:Histogram中還可以對物件進行Group,比如選擇Group By Package更方便檢視自己Package中的物件資訊。

2.3 MAT分析hprof來定位記憶體洩露的原因所在

2.3.1 Dump出記憶體洩露“當時”的記憶體映象hprof,分析懷疑洩露的類;

這裡寫圖片描述

2.3.2 把上面2.2得出的這些嫌疑排查

(1)進入Histogram,過濾出某一個嫌疑物件類;
這裡寫圖片描述
(2)然後分析持有此類物件引用的外部物件(在該類上面點選右鍵List Objects—>with incoming references);
這裡寫圖片描述
(3)再過濾掉一些弱引用、軟引用、虛引用,排除這些容易被回收的引用,因為它們遲早可以被GC幹掉不屬於記憶體洩露。 (在類上面點選右鍵Merge Shortest Paths to GC Roots————>exclude all phantom/weak/soft etc.references);
這裡寫圖片描述

(4)逐個分析每個物件的GC路徑是否正常。此時就要進入程式碼分析此時這個物件的引用持有是否合理,這就要考經驗和體力了!例子:
分析:上面的例子中,旋轉屏幕後MainActivity有兩個,肯定MainActivity發生洩露了,那誰導致他洩露的呢?原來是我們的CommonUtils類持有了旋轉之前的那個MainActivity,那是否合理?
解答:結合邏輯判斷當然不合理,由此找到記憶體洩露根源是CommonUtils類持有了該MainActivity例項造成的。

(5)怎麼解決?罪魁禍首找到了,怎麼解決應該不難了,不同情況解決辦法不一樣,要靠你的智慧了。例子:
分析:context.getapplictioncontext()可以嗎?
解答:可以。只要讓CommonUtils類不直接持有MainActivity的例項就可以了。

3 如何判斷一個應用裡面記憶體洩露避免得很好

當app退出的時候,這個程序裡面所有的物件應該就都被回收了,尤其是很容易被洩露的(View,Activity)是否還在記憶體當中。

解答:可以讓app退出以後,檢視系統該程序裡面的所有的View、Activity物件是否為0。

工具:使用AndroidStudio——>Android Monitor——>System Information——>Memory Usage檢視Objects裡面的views和Activity的數量是否為0。如圖:
(1)檢視方法
這裡寫圖片描述
(2)存在記憶體洩漏的app退出報告
這裡寫圖片描述
(3)無記憶體洩漏的app退出報告
這裡寫圖片描述

4 引起記憶體洩漏的情景分析

5 參考連結