1、背景
記錄一次內存分析的簡單實踐,目的是找出佔用內存較大的對象和無效的內存分配
2、工具
2.1、 DDMS或者Android Studio
DDMS:抓取內存快照
Android Studio的Profiler:抓取內存快照並分析(支持android 5.0以上)
2.2、 MAT(Memory Analyzer)
內存快照文件分析工具
3、步驟
3.1、 抓取內存快照
DDMS支持5.0以下的系統,以DDMS爲例。
選擇目標apk,並抓取內存快照,可以先GC幾次確保內存快照準確。
生成hprof文件並轉換。這時生成的文件不能直接使用,要經過轉換。轉換工具在Android SDK的platform-tools目錄下,如:
xxx\Android\SDK\platform-tools\hprof-conv.exe -z xxx\xxx\src.hprof xxx\xxx\src-conv.hprof
生成的src-conv.hprof文件就可以在mat中打開了。
3.2 分析內存快照
3.2.1、總覽
打開上一步得到的hprof文件
這裏可以看到大致的內存佔用信息,放到餅狀圖上,還能看到具體的佔用對象,如:
這裏看到佔用最多的是bitmap,其次是glide。
3.2.2、Dominator Tree
直觀地列出大對象
3.2.3、Histogram統計
Histogram可以統計出各個對象佔用的具體大小,並可以排序、篩選等。比如這裏按Retained Heap降序排
能看到具體是什麼對象,佔用了多少內存,對象有多少個等信息。
3.2.4 with outgoing/incoming references
列出引用對象
- with outgoing references:我引用了誰
- with incoming references:誰引用了我
這裏bitmap佔用最大,選中bitmap右鍵:
比如查看什麼對象引用了bitmap(with incoming references):
可以看到有兩個對象引用了bitmap,分別是IndexLoadingDialog裏的mIvLoading和TextSeekBar裏的mProgressDrawable。
3.2.5 Merge Shortest Paths to GC Roots
如果上面的方法還不夠直接的話,可以使用Merge Shortest Paths to GC Roots
可以篩選引用類型:如去除弱引用、軟引用等,這裏選只保留強應用,即exclude all phantom/weak/soft etc. references
這裏很直觀的顯示了引用對象。
3.2.6 利用表達式篩選
在Histogram統計界面,可以利用正則表達式篩選出想看的類,比如使用包名篩選:
針對性的去查找大內存對象。
3.3 優化大內存對象
通過上面的分析,已經大致知道了什麼對象佔用內存比較大和引用位置。就可以針對具體的對象進行優化了,比如這裏圖片壓縮一下、TextSeekBar只用於下載更新apk時使用,可以用ViewStub標籤延遲加載等。假設IndexLoadingDialog裏的mIvLoading可以去掉,去掉之後重複上面的步驟:
可以看到內存已經從之前的4.2m降到了345k。
4、結語
mat還可以分析內存泄漏,比如打開/關閉activity多操作幾次,查看內存快照中activity的對象個數,就可以判斷是否存在泄漏了。雖然看了不少內存優化的文章、介紹,但是一直都沒有什麼實感,這次終於有了把理論用到了實踐當中的感覺。