Activity記憶體泄漏分析
- 前言
- 問題背景
- 使用dumpsys meminfo獲取應用記憶體資訊
- DDMS抓取hprof檔案
- MAT分析hprof
前言
這是第一次書寫博客,作業也有幾年了,雖然寫了很多的筆記,但是都屬于閉門造車,有時候也不知道自己記錄的經驗有沒有問題,或者是不是有理解不到位的地方,因此想做一下改變,將自己記錄的東西發到博客上,集思廣益,如果我的博客對解決你的問題有幫助,那也是一件不錯的事情,如果覺得我分享內容有錯誤,也請指出來,方便本人改正免得誤導大家,好了,接下來開始分享一下我最近遇到的一個Activity記憶體泄漏的問題,主要講一下遇到記憶體泄漏,如何分析定位問題的,下面分析中的例子是我自己根據原來的問題,書寫的一個樣例代碼,
問題背景
專案上有一個音樂應用,客戶報該應用在使用一段時間后,記憶體占用較高,高達了600多M,正常應該在300M左右,
使用dumpsys meminfo獲取應用記憶體資訊
使用指令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檔案來分析,
DDMS抓取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
MAT分析hprof
- 使用MAT工具打開hprof檔案,截圖如下:

- 選擇Histogram查看應用中每個Class的物件個數(先查看物件),打開后界面如下:
首先對圖中這些條目代表什么意思進行一下說明,Objects代表該物件的個數,Shallow Heap表示當前物件占用的記憶體,不包括當前物件內包含的物件的大小,Retained Heap表示當前物件包括物件內的子物件一共占用的記憶體大小,所以Retained Heap會比Shallow Heap大;
由于一個應用的hprof檔案中物件太多,如果想要快速找到SecondActivity,這里其實還有一種辦法就是MAT工具的OQL功能,我們可以通過在OQL里面輸入“select * from instanceof android.app.Activity”,點擊左上角感嘆號圖示,執行Query陳述句,可以快速查找,具體截圖如下:

- 我寫的Demo,反復進入的Activity的名字為com.example.myapplication.SecondActivity;從第二點的第一張截圖中可以看出該Activity的物件個數達到了30個,正常情況下退出該Activity后,該Activity的物件應該被回收才對,所以很明顯我寫的這個SecondActivity存在記憶體泄漏,
- 選中SecondActivity,右鍵選擇merge shortest Paths to GC Roots->exclude all
phantom/weak/soft .ect references排除所有的弱參考,看是否有GC
Roots持有該物件的強參考,如果沒有GC Roots則說明這個物件不存在記憶體泄漏,最終是會被GC回收的,執行操作后得到如下截圖:
上圖中com.android.internal.policy.DecorView$TileScreenWindowModeListener作為GC Roots(GC Roots物件左下角有一個小圓點),持有了SecondActivity的mContext,而我們知道Activity在退出后,里面的資源物件是會被系統回收的,這里有GC Roots持有了Activity的強參考,導致該Activity不能被GC回收,因此發生記憶體泄漏,具體TileScreenWindowModeListener里面為什么會在SecondActivity退出后仍然持有它的mContext,就需要具體分析代碼了,
這里對點擊Object物件后,右鍵的幾個選項進行一下說明:List Objects中with outgoing references(表示的是當前物件,參考了哪些外部參考)和with incoming references(表示的是當前查看的物件,被哪些外部物件參考),一般當前物件泄漏了就是物件還被外部物件持有參考,無法被釋放,
參考鏈接如下: https://www.jianshu.com/p/e39fa2900960
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/148634.html
標籤:其他
上一篇:Codeforces Round #673 (Div. 2) D. Make Them Equal
下一篇:Android Studio添加android.support.v4包的依賴(解決V4的FragmentManager的錯誤)
