Android進階——性能優化之MAT的使用

前言

在開發過程中,經常遇到測試提出的內存增長明顯的測試報告或者是測試提出的OOM問題,此時就需要跟測試獲取hprof文件對內存增長和內存泄漏等問題進行排查,那麼MAT就是我們必須學會的排查內存增長或泄漏等問題的工具

概念

  • MAT:MemoryAnalyzer,內存的分析工具,通過工具可以分析堆內存的使用情況和檢測內存泄漏等問題
  • hprof文件:指的是當前Android堆內存的快照情況,當前設備的堆內存會全部保存在hporf中,可以通過MAT工具進行打開

分析內存

1、生成hprof文件導出

這裏寫圖片描述

2、打開MAT 導入我們的2個hprof文件

其中1個是旋轉多次屏幕之後的文件(屬於內存泄漏部分),另1個是沒有內存泄漏的文件,通過以下操作打開:Open File->選擇文件->Leak Suspects Report->Finish

這裏寫圖片描述

在打開文件的時候,經常會遇到Parsing heap dump from xxx has encountered a problem. Error opening heap dump xxx.hprof這個錯誤,由於MAT是適用於eclipse的版本,需要將導出來的hprof文件轉換一下格式,通過Android SDK自帶的工具,在命令行中輸入

hprof-conv 1.hprof 2.hprof

3、在OverView視圖找到Histogram

這裏寫圖片描述

4、進入Histogram,查看內存使用情況

該視圖以Class類的維度展示每個Class類的實例存在的個數、佔用的[Shallow內存]和[Retained內存]大小,可以分別排序顯示

  • Objects:當前Class的實例存在的個數
  • Shallow內存:代表當前類所有實例所佔用的內存大小
  • Retained內存:代表從該類實例沿着reference chain往下所能收集到的其他類實例的Shallow Heap(Size)總和

這裏寫圖片描述

5、分別在2個hprof文件中做如下動作,將Histogram視圖添加到對比欄

這裏寫圖片描述

6、點擊對比

這裏寫圖片描述

7、通過比較後就會生成一個比較結果表ComPared Tables,我們通過輸入我們自己的包名,找到對應的比較結果

這裏寫圖片描述

並且在上面的可以設置不同的對比方式

在這裏插入圖片描述

8、通過比較發現我們的程序存在內存泄漏,那麼下面就要在內存泄漏的文件中找到泄漏的根源

這裏寫圖片描述

9、回到泄漏的文件中,找到Histogram入口,輸入我們發現泄漏的類名

這裏寫圖片描述

10、通過右鍵,查看MainActivity實例被哪些對象使用

這裏寫圖片描述

  • with outgoing references:查看當前對象持有的外部對象引用,從箭頭可以看出,當前對象下面還有誰
  • with incoming references:查看當前對象被哪些外部對象所引用,從箭頭可以看出,當前對象上頭還有誰

這裏寫圖片描述

這裏寫圖片描述

11、由於使用的對象大多數爲系統級別的引用,很難讓我們去分辨具體的內存泄漏,所以我們通過遍歷GC Root樹去將那些有可能被GC回收的實例將他們去除,右鍵取出可能會被GC的虛/弱/軟引用

  • Paths to GC Roots:從當前對象到GC roots的調用鏈,這個調用鏈解釋了爲什麼當前對象還能存活
  • Merge Shortest Paths to GC roots:從GC roots到一個或一組對象的調用樹

由於Paths to GC roots是針對單個對象的,故在Histogram視圖無法使用,可以在dominator_tree上用

這裏寫圖片描述

12、最後只剩下我們泄漏的內存

這裏寫圖片描述

常用用法

1、Dominator Tree

該視圖以實例對象的維度展示當前堆內存中Retained Heap佔用最大的對象,以及依賴這些對象存活的對象的樹狀結構

在這裏插入圖片描述

2、Immediate Dominator

右鍵選擇Immediate Dominator來查看某個對象被誰直接引用

在這裏插入圖片描述

3、Duplicate Classes

該視圖列出被加載多次的類,結果按類加載器進行分組,目標是加載同一個類多次被類加載器加載。使用該工具很容易找到部署應用的時候使用了同一個庫的多個版本

在這裏插入圖片描述

4、Top Consumers

列出佔用總堆內存超過1%的對象

在這裏插入圖片描述

5、Thread Overview

該視圖可以看到:線程對象/線程棧信息、線程名、Shallow Heap、Retained Heap、類加載器、是否Daemon線程等信息

在這裏插入圖片描述

6、Group分組

可以選擇以另一種分組方式顯示(默認是No Grouping(objects),即以對象維度分組)

在這裏插入圖片描述

7、Find Object by address

通過十六進制的地址查找對應的對象

在這裏插入圖片描述

8、OQL(Object Query Language)

類似SQL查詢語言,可以過濾一些想要的內存信息

在這裏插入圖片描述

  • 查找包名
select * from com.example.mat.Listener
  • 查找size=0並且未使用過的集合
select * from java.util.HashMap where size=0 and modCount=0
select * from java.util.Hashtable where count=0 and modCount=0
select * from java.util.ArrayList where size=0 and modCount=0
  • 查找所有的Activity
select * from instanceof android.app.Activity

分析報告

從工具欄入口可以選擇MAT默認提供的一些報告工具,有利於我們分析問題

在這裏插入圖片描述

1、Heap Dump Overview

查看整個堆的概括情況,例如:堆內存大小、對象個數、類的個數、類加載器的個數、GC root的個數、堆內存文件的格式、文件的創建時間、位置等信息

在這裏插入圖片描述

2、Leak Suspects

查看潛在的內存泄漏問題

在這裏插入圖片描述

3、Top Components

針對那些佔用堆內存超過整個堆內存1%大小的組件做一系列的分析

在這裏插入圖片描述

分析集合

1、分析集合大小

分析集合的大小,可以更合理的去初始化集合的大小,達到性能合理利用

  • 篩選目標對象

在這裏插入圖片描述

  • 查找被回收時那些將被GC回收的對象集合

在這裏插入圖片描述

  • 篩選指定的Object(Hash Map,ArrayList)並按照集合大小進行分組

在這裏插入圖片描述

  • 查看哪個對象正在引用當前大小爲0的集合

在這裏插入圖片描述

2、分析集合填充率

集合填充率是可以更好反映集合在自身大小確定的情況下,是否被完全填充滿,推斷出哪些集合具有預分配內存能力,填充率 = size / capacity(容量)

  • Collections fill ratio

在這裏插入圖片描述

  • 查看填充率

在這裏插入圖片描述

3、分析集合碰撞率

集合碰撞率指的是Hash碰撞,通過減少Hash碰撞衝突能優化集合性能,碰撞率 = 碰撞的實體/Hash表中所有實體

  • Map Collision Ratio

在這裏插入圖片描述

  • Immediate dominators

在這裏插入圖片描述

4、分析集合鍵值對

  • Hash Entries查看key value

在這裏插入圖片描述

經驗總結

1、在查找內存泄漏問題時

通常內存泄漏發生在IO流,內部類,Handler,Activity,Cursor,Receiver等組件中

  • 如果是懷疑Activity組件泄漏的時候,可以使用Dominator Tree功能,優先過濾Activity字段快速找到是否存在泄漏的對象
  • 如果是懷疑Activity組件泄漏的時候,可以通過OQLselect * from instanceof android.app.Activity並移除所有虛/弱/軟引用

2、在查找內存增長問題時

通常內存增長的情況有很多種,具體還是得找到懷疑點,看代碼邏輯解決

  • 可以使用Leak Suspects Report功能,查看工具分析出來的內存佔用情況,優先分析報告中提出來的問題
  • 可以使用Dominator Tree功能,過濾項目包名,通過Retained Heap排序,快速找到內存佔用大的對象,進一步在代碼中排查
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章