這是第一次書寫部落格,工作也有幾年了,雖然寫了很多的筆記,但是都屬於閉門造車,有時候也不知道自己記錄的經驗有沒有問題,或者是不是有理解不到位的地方。因此想做一下改變,將自己記錄的東西發到部落格上,集思廣益。如果我的部落格對解決你的問題有幫助,那也是一件不錯的事情。如果覺得我分享內容有錯誤,也請指出來,方便本人改正免得誤導大家。好了,接下來開始分享一下我最近遇到的一個Activity記憶體漏失的問題,主要講一下遇到記憶體漏失,如何分析定位問題的。下面分析中的例子是我自己根據原來的問題,書寫的一個樣例程式碼。
專案上有一個音樂應用,客戶報該應用在使用一段時間後,記憶體佔用較高,高達了600多M,正常應該在300M左右。
使用指令adb shell dumpsys meminfo + 應用包名 檢視應用記憶體使用情況,例如:
1.Native Heap是native層的記憶體堆疊,Dalvik Heap是java層的記憶體堆疊,如果這二者加起來的記憶體佔用超過了應用最大記憶體限制就會報OOM異常,剩下的.so mmap是 C 庫程式碼佔用的內 存,.jar mmap是Java 檔案程式碼佔用的記憶體 ,.apk mmap是apk程式碼佔用的記憶體,.dex mmap是Dex 檔案程式碼佔用的記憶體。
2. Objects中的Activities表示當前記憶體中的activity物件的個數,啟動一個activity就會生成一個activity物件,當退出activity的時候,activity物件就會被釋放,所以反覆的進出一個activity介面然後檢視Activities的個數有沒有保持不變,如果增加了,那麼就說明這個activity物件沒有被釋放,也就是說可能存在記憶體漏失,但是具體哪裡洩漏了,需要繼續分析。
3.當前這份dump出來的資料,是我寫的Demo中,MainActivity和SecondActivity之間來回切換後的結果,可以看到Objects中的Activities個數達到了31個,我這裡沒有貼出來應用原始的dumpsys meminfo資料,否則也可以發現Total這項總記憶體也在一直增加,且多次GC後回落的也並不明顯,說明當前應用可能存在記憶體漏失,接下來則需要通過抓取應用的hprof檔案來分析。
通過Android SDK中自帶的工具Android Device Monitor(DDMS)抓取應用的hprof檔案,monitor工具的地址在Sdk/tools目錄下。
首先在ubuntu終端輸入monitor開啟程式
點選右上角選擇DDMS工具,找到你需要偵錯的應用包名,選中指定程序後(例如com.example.myapplication),點選介面左上角的"update
Heap"按鈕,獲取應用的記憶體資訊,截圖如下:
上圖是應用的Heap資訊是應用初始的記憶體資訊,主要關注data object這項,其中Count是總物件的個數,Totle Size是java物件佔用的總記憶體。比如當前的這個Demo,反覆的進入SecondActivity,其中Count的個數在不斷增加,退出該SecondActivity後,執行」Cause GC」並等待一段時間後,發現Count個數以及Total Size並沒有明顯回落,那麼這個應用可能就存在記憶體漏失,需要具體分析一下。我這邊使用的記憶體分析工具為MemoryAnalyzer-1.8.1.20180910-linux.gtk.x86_64.zip,這個工具在網上很容易下載到,這裡就不提供連線了;
抓取hprof檔案 ,多次點選「Cause GC」觸發一下系統的GC記憶體回收,然後等待GC完畢,此時是程式最開始佔用記憶體的情況,接下來反覆的進入某個Activity,操作完畢後,多次點選」Cause GC"執行記憶體回收,然後點選DDMS介面左上角的"dump hprof file"按鈕抓取Heap檔案,一般檔案預設名為:com.example.myapplication.hprof;這時候抓取的hprof檔案是不能直接被MAT工具開啟的,因此需要進行一下轉換;
使用hprof-conv工具將Heap檔案轉換為MAT工具可以讀取的格式,Ubuntu的小夥伴可以將位於SDK/platform-tools下的hprof-conv設定到環境變數中。首先開啟 ~/.bashrc檔案在末尾新增:export PATH=/home/xxx/Android/Sdk/platform-tools:$PATH 然後在終端使用如下指令轉換hprof檔案:hprof-conv source.hprof target.hprof
首先對圖中這些條目代表什麼意思進行一下說明,Objects代表該物件的個數,Shallow Heap表示當前物件佔用的記憶體,不包括當前物件內包含的物件的大小,Retained Heap表示當前物件包括物件內的子物件一共佔用的記憶體大小,所以Retained Heap會比Shallow Heap大;
由於一個應用的hprof檔案中物件太多,如果想要快速找到SecondActivity,這裡其實還有一種辦法就是MAT工具的OQL功能,我們可以通過在OQL裡面輸入「select * from instanceof android.app.Activity」,點選左上角感嘆號圖示,執行Query語句,可以快速查詢,具體截圖如下:
參考連結如下: https://www.jianshu.com/p/e39fa2900960