1. 程式人生 > >安卓開發中記憶體問題分析(一)工具篇

安卓開發中記憶體問題分析(一)工具篇

記憶體洩漏和記憶體溢位是安卓開發中經常碰到的問題,如何能夠快速有效的發現並追蹤記憶體洩漏或者記憶體溢位的源頭,是每個開發者都需要掌握的技巧,今天我給大家帶來常見的記憶體分析工具使用方法,希望對大家今後的開發帶來幫助。

使用Eclipse分析應用記憶體使用情況

具體步驟如下: 
1.啟動eclipse後,切換到DDMS透檢視,並通過Window-ShowView開啟Devices檢視、Heap檢視

2.連線手機或者模擬器後,在DDMS的Devices檢視中將會顯示手機裝置或模擬器的序列號,以及裝置中正在執行的部分程序資訊

3.點選選中想要監測的程序,然後再點選下Update Heap讓其自動找到我們執行中應用的程序

這裡寫圖片描述 
這裡寫圖片描述

4.點選Heap檢視中的“Cause GC”按鈕,請求一次GC操作(PS:當記憶體使用資訊第一次顯示以後,無須再不斷的點選“Cause GC”,Heap檢視介面會定時重新整理,在對應用的不斷的操作過程中就可以看到記憶體使用的變化)

這裡寫圖片描述

5.點選Cause GC之後就可以看到我們應用的記憶體情況如下圖:

這裡寫圖片描述
6.具體使用過程中,我們要關注 Heap檢視中部有一個Type叫做data object,即資料物件,也就是我們的程式中大量存在的類的物件。在data object一行中有一列是“Total Size”,其值就是當前程序中所有Java資料物件的記憶體總量,如果大家想要看“Total Size”是分配的具體資訊可以點選“data object這一行來檢視詳細資訊,如下圖:

這裡寫圖片描述

在使用中 “Total Size”這個值的大小決定了是否會有記憶體洩漏。我們可以通過不斷的操作當前應用,同時觀察data object的Total Size值的變化情況;正常情況下Total Size值都會穩定在一個有限的範圍內,也就是說由於程式中的的程式碼良好,沒有造成物件不被垃圾回收的情況,所以說雖然我們不斷的操作會不斷的生成很多物件,而在虛擬機器不斷的進行GC的過程中,這些物件都被回收了,記憶體佔用量會會落到一個穩定的水平;反之如果程式碼中存在沒有釋放物件引用的情況,則data object的Total Size值在每次GC後不會有明顯的回落,隨著操作次數的增多Total Size的值會越來越大,正常情況下,一個虛擬機器的程序的記憶體在64M, 如果記憶體洩漏會發現 Heap Size 在不斷的逼近 64M, 一旦達到這個值時,就會出現記憶體洩漏退出應用等情況。 
Total Size的值越來越大時,我們按下“Dump HPROF File”按鈕,這個時候會提示設定hprof檔案的儲存路徑。儲存後,我們可以使用MAT工具來分析是哪些操作造成了記憶體洩漏。

使用MAT分析hprof檔案

Eclipse Memory Analyzer(MAT)是著名的跨平臺整合開發環境 Eclipse Galileo 版本的 33 個組成專案中之一,它是一個功能豐富的JAVA 堆轉儲檔案分析工具,可以幫助你發現記憶體漏洞和減少記憶體消耗。對於大型 JAVA 應用程式來說,再精細的測試也難以堵住所有的漏洞,即便我們在測試階段進行了大量卓有成效的工作,很多問題還是會在生產環境下暴露出來,並且很難在測試環境中進行重現。JVM 能夠記錄下問題發生時系統的部分執行狀態,並將其儲存在堆轉儲 (Heap Dump) 檔案中,從而為我們分析和診斷問題提供了重要的依據。 
官方網站:http://www.eclipse.org/mat/ 
從官網中下載最新的MAT工具,開啟後如下圖:

這裡寫圖片描述

廢話不多說,MAT的使用步驟如下: 
1.開啟 MAT 工具,File–>Open Heap Dump… 選擇你剛剛儲存的 hprof 檔案開啟 
此時,會彈出一個錯誤,如下圖所示:

這裡寫圖片描述

不要以為是 MAT 工具版本不對,其實是 Android 的 hprof 檔案在這裡需要進行轉換一下格式才可以使用 MAT 開啟,使用AndrodiSDK/tools/hprof-conv轉化hprof檔案, 
首先,要通過控制檯進入到你的 android sdk tools 目錄下 
例如 hprof-conv input.hprof out.hprof 
再使用MAT工具開啟轉換後的 hprof 檔案,就能看到完整的記憶體使用分析報告了

這裡寫圖片描述

2.如下所示是 MAT 分析記憶體使用的主介面:

這裡寫圖片描述

點選上圖中的 Reports –>Leak Suspects 則可以進一步看到更詳細的記憶體洩漏疑點

這裡寫圖片描述

在其中懷疑的地方,點選 Details 就可以看到具體的記憶體使用情況了。

這裡寫圖片描述

從上圖中我們可以看到記憶體聚集點是一個擁有大量物件的集合,這個物件集合中儲存了大量 Person 物件的引用,就是它導致的記憶體洩露。 
3.另外我們經常會使用Histogram查詢

這裡寫圖片描述

在某一項上右鍵開啟選單選擇 list objects ->with incoming references 將列出該類的例項,也可以點選表頭進行排序,在表的第一行可以輸入正則表示式來匹配結果

這裡寫圖片描述

4.在選中某一項上右鍵開啟選單選擇 list objects ->with incoming refs 將列出該類的例項:

這裡寫圖片描述

在新開啟的Tab頁面中展示了物件間的引用關係。

這裡寫圖片描述

如果想檢視某個例項沒被釋放的原因,可以右健 Path to GC Roots–>exclue all phantom/weak/soft etc. reference :這樣變可以快速檢視某個物件的 GC Root

這裡寫圖片描述

5.有時候為查詢記憶體洩漏,我們通常需要兩個Dump結果作對比,這時我們可以開啟 Navigator History面板,將兩個表的 Histogram結果都新增到 Compare Basket中去 :

這裡寫圖片描述

這裡寫圖片描述

然後點選面板右上角的紅色歎號,得到對比結果:

這裡寫圖片描述

這裡寫圖片描述

同時也可以改變對比條件:

這裡寫圖片描述

使用AndroidStudio分析應用記憶體使用情況

現在開發者普遍使用AndroidStudio進行開發,關於記憶體使用的分析更加人性化,其內部也預設支援hprof檔案的分析,下面帶領大家一起學習一下: 
(一) 使用AndroidStudio追蹤記憶體使用狀況,開啟Android Monitor面板(PS:快捷鍵Alt+6),點選Memory選項卡

這裡寫圖片描述

(二) 使用AndroidStudio分析hprof檔案,具體步驟如下: 
1. 在AndroidStudio選單欄中開Android Device Monitor,如下圖:

這裡寫圖片描述

2.在Android Device Monitor介面中選在你要分析的應用程式的包名,同時點選Update Heap用來更新統計資訊,然後點選Cause GC即可檢視當前堆的使用情況,如下圖

這裡寫圖片描述

3.點選Dump HPROF file,將該應用當前的記憶體資訊儲存成hprof檔案,存放到你所指定的路徑,如下圖

這裡寫圖片描述

4.在File選單欄中開啟剛才儲存的hprof檔案(當然為了省事,你也可以直接將hprof檔案拖入AndroidStudio中)

這裡寫圖片描述

5.在開啟的hprof檔案中,我們可以很容的找到自己應用程式的包名,開啟對應包就可以看到記憶體使用情況。

這裡寫圖片描述

使用LeakCanary分析應用記憶體使用情況

這裡寫圖片描述

LeakCanary 是一個開源的在debug版本中檢測記憶體洩漏的java庫。 
GitHub地址:https://github.com/square/leakcanary 
(一)配置說明:

這裡寫圖片描述

(二)使用案例:

這裡寫圖片描述

建立一個RefWatcher例項,然後給它一個物件讓它觀察: 
refWatcher.watch(schrodingerCat); 
當檢測出洩漏的時候,你會自動得到一個漂亮的洩漏線索:

  • GC ROOT static Docker.container
  • references Box.hiddenCat
  • leaks Cat instance

然後只需幾行程式碼,LeakCanary就能自動檢測Activity的洩漏:

這裡寫圖片描述

最終當出現記憶體不足時,你將看到如下通知介面:

這裡寫圖片描述

也就是說,啟用LeakCanary之後,可以幫助我們更加方便的發現和修復許多記憶體問題。