Android內(nèi)存優(yōu)化工具:MAT

一、獲取HPROF文件

HPROF文件是MAT能識(shí)別的文件,HPROF文件存儲(chǔ)的是特定時(shí)間點(diǎn),java進(jìn)程的內(nèi)存快照。有不同的格式來(lái)存儲(chǔ)這些數(shù)據(jù),總的來(lái)說(shuō)包含了快照被觸發(fā)時(shí)java對(duì)象和類(lèi)在heap中的情況。由于快照只是一瞬間的事情,所以heap dump中無(wú)法包含一個(gè)對(duì)象在何時(shí)、何地(哪個(gè)方法中)被分配這樣的信息。
這個(gè)文件可以使用Memory Profiler導(dǎo)出(詳見(jiàn)Android內(nèi)存優(yōu)化工具:Memory Profiler)

二、MAT主要界面介紹

得到對(duì)應(yīng)的文件后,要使用Android SDK自帶的的工具(hprof-conv 位置在sdk/platform-tools/hprof-conv)進(jìn)行轉(zhuǎn)換

hprof-conv heap-original.hprof heap-converted.hprof

用MAT打開(kāi)轉(zhuǎn)換過(guò)的HPROF文件是,就有一個(gè)彈窗詢(xún)問(wèn)展示哪一種報(bào)告:


image.png
  • 內(nèi)存泄漏報(bào)告
    自動(dòng)檢查堆轉(zhuǎn)儲(chǔ)中是否存在嫌疑內(nèi)存泄漏,報(bào)告哪些對(duì)象保持活動(dòng)以及它們?yōu)楹螞](méi)有被垃圾收集器回收
  • Component Report
    對(duì)內(nèi)存中的對(duì)象進(jìn)行分析并發(fā)現(xiàn)內(nèi)存問(wèn)題(重復(fù)的string,空集合,弱引用等)

選擇內(nèi)存泄漏報(bào)告后,打開(kāi)看的的第一個(gè)界面如下圖所示:


內(nèi)存泄漏報(bào)告.png

OverView界面:

OverView界面.png

我們需要關(guān)注的是下面的Actions區(qū)域:

  • Histogram:列出內(nèi)存中的對(duì)象,對(duì)象的個(gè)數(shù)以及大小


    Histogram.png

    默認(rèn)以類(lèi)名的形式展示,你可以選擇不同的方式,有下面四種:


    展示形式.png
  • Dominator Tree:列出最大的對(duì)象以及其依賴(lài)存活的Object (大小是以Retained Heap為標(biāo)準(zhǔn)排序的)。注意這個(gè)地方是對(duì)象而不是類(lèi)了,這個(gè)視圖是用來(lái)發(fā)現(xiàn)大內(nèi)存對(duì)象的。這些對(duì)象都可以展開(kāi)查看更詳細(xì)的信息


    Dominator Tree.png
  • Top Consumers : 通過(guò)圖形列出最大的object


    Top Consumers .png
  • Duplicate Class:檢測(cè)由多個(gè)類(lèi)加載器加載的類(lèi)。

  • Thread Overview:展示每個(gè)線程的名字、stack、局部變量、Retained Heap等信息


    Thread Overview.png

一般Histogram、Dominator Tree、Thread Overview是最常用的

三、MAT中一些概念介紹

Shallow heap

Shallow size就是對(duì)象本身占用內(nèi)存的大小,不包含其引用的對(duì)象。

  • 常規(guī)對(duì)象(非數(shù)組)的Shallow size有其成員變量的數(shù)量和類(lèi)型決定。
  • 數(shù)組的shallow size有數(shù)組元素的類(lèi)型(對(duì)象類(lèi)型、基本類(lèi)型)和數(shù)組長(zhǎng)度決定
    因?yàn)椴幌馽++的對(duì)象本身可以占大量?jī)?nèi)存,java的對(duì)象成員都是些引用。真正的內(nèi)存都在堆上,看起來(lái)是一堆原生的byte[], char[], int[],所以我們?nèi)绻豢磳?duì)象本身的內(nèi)存,那么數(shù)量都很小。所以我們看到Histogram圖是以Shallow size進(jìn)行排序的,排在第一位第二位的是byte,char 。

Retained Heap

Retained Heap的概念,它表示如果一個(gè)對(duì)象被釋放掉,那會(huì)因?yàn)樵搶?duì)象的釋放而減少引用進(jìn)而被釋放的所有的對(duì)象(包括被遞歸釋放的)所占用的heap大小。于是,如果一個(gè)對(duì)象的某個(gè)成員new了一大塊int數(shù)組,那這個(gè)int數(shù)組也可以計(jì)算到這個(gè)對(duì)象中。相對(duì)于shallow heap,Retained heap可以更精確的反映一個(gè)對(duì)象實(shí)際占用的大小

Retained Heap并不總是那么有效。例如我在A里new了一塊內(nèi)存,賦值給A的一個(gè)成員變量。此時(shí)我讓B也指向這塊內(nèi)存。此時(shí),因?yàn)锳和B都引用到這塊內(nèi)存,所以A釋放時(shí),該內(nèi)存不會(huì)被釋放。所以這塊內(nèi)存不會(huì)被計(jì)算到A或者B的Retained Heap中。

為了計(jì)算Retained Memory,MAT引入了Dominator Tree。加入對(duì)象A引用B和C,B和C又都引用到D(一個(gè)菱形)。此時(shí)要計(jì)算Retained Memory,A的包括A本身和B,C,D。B和C因?yàn)楣餐肈,所以他倆的Retained Memory都只是他們本身。D當(dāng)然也只是自己。MAT改變了對(duì)象引用圖,而轉(zhuǎn)換成一個(gè)對(duì)象引用樹(shù)。在這里例子中,樹(shù)根是A,而B(niǎo),C,D是他的三個(gè)兒子。B,C,D不再有相互關(guān)系。把引用圖變成引用樹(shù),計(jì)算Retained Heap就會(huì)非常方便,顯示也非常方便。對(duì)應(yīng)到MAT UI上,在dominator tree這個(gè)view中,顯示了每個(gè)對(duì)象的shallow heap和retained heap。然后可以以該節(jié)點(diǎn)位樹(shù)根,一步步的細(xì)化看看retained heap到底是用在什么地方了。

為了糾正這點(diǎn),MAT中點(diǎn)擊右鍵,可以List objects中選擇with outgoing references和with incoming references。這是個(gè)真正的引用圖的概念,

  • outgoing references :表示該對(duì)象的出節(jié)點(diǎn)(被該對(duì)象引用的對(duì)象)。
  • incoming references :表示該對(duì)象的入節(jié)點(diǎn)(引用到該對(duì)象的對(duì)象)。

GC Root

GC發(fā)現(xiàn)通過(guò)任何reference chain(引用鏈)無(wú)法訪問(wèn)某個(gè)對(duì)象的時(shí)候,該對(duì)象即被回收。名詞GC Roots正是分析這一過(guò)程的起點(diǎn),例如JVM自己確保了對(duì)象的可到達(dá)性(那么JVM就是GC Roots),所以GC Roots就是這樣在內(nèi)存中保持對(duì)象可到達(dá)性的,一旦不可到達(dá),即被回收。通常GC Roots是一個(gè)在current thread(當(dāng)前線程)的call stack(調(diào)用棧)上的對(duì)象(例如方法參數(shù)和局部變量),或者是線程自身或者是system class loader(系統(tǒng)類(lèi)加載器)加載的類(lèi)以及native code(本地代碼)保留的活動(dòng)對(duì)象。所以GC Roots是分析對(duì)象為何還存活于內(nèi)存中的利器。

四、發(fā)現(xiàn)內(nèi)存泄漏對(duì)象

在Histogram或者Domiantor Tree的某一個(gè)條目上,右鍵可以查看其GC Root Path:


GC Root Path.png

點(diǎn)擊Path To GC Roots —> exclude all phantom/week/soft etc. references


GC Roots.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容