內(nèi)存泄露從入門到精通三部曲之排查方法篇
最原始的內(nèi)存泄露測試
重復(fù)多次操作關(guān)鍵的可疑的路徑,從內(nèi)存監(jiān)控工具中觀察內(nèi)存曲線,是否存在不斷上升的趨勢且不會在程序返回時明顯回落。 這種方式可以發(fā)現(xiàn)最基本,也是最明顯的內(nèi)存泄露問題,對用戶價值***,操作難度小,性價比極高。
MAT內(nèi)存分析工具
2.1 MAT分析heap的總內(nèi)存占用大小來初步判斷是否存在泄露
在Devices 中,點(diǎn)擊要監(jiān)控的程序。
點(diǎn)擊Devices視圖界面中最上方一排圖標(biāo)中的“Update Heap”
點(diǎn)擊Heap視圖
點(diǎn)擊Heap視圖中的“Cause GC”按鈕
到此為止需檢測的進(jìn)程就可以被監(jiān)視。
Heap視圖中部有一個Type叫做data object,即數(shù)據(jù)對象,也就是我們的程序中大量存在的類類型的對象。在data object一行中有一列是“Total Size”,其值就是當(dāng)前進(jìn)程中所有Java數(shù)據(jù)對象的內(nèi)存總量,一般情況下,這個值的大小決定了是否會有內(nèi)存泄漏??梢赃@樣判斷:
進(jìn)入某應(yīng)用,不斷的操作該應(yīng)用,同時注意觀察data object的Total Size值,正常情況下Total Size值都會穩(wěn)定在一個有限的范圍內(nèi),也就是說由于程序中的的代碼良好,沒有造成對象不被垃圾回收的情況。
所以說雖然我們不斷的操作會不斷的生成很多對象,而在虛擬機(jī)不斷的進(jìn)行GC的過程中,這些對象都被回收了,內(nèi)存占用量會會落到一個穩(wěn)定的水平;反之如果代碼中存在沒有釋放對象引用的情況,則data object的Total Size值在每次GC后不會有明顯的回落。隨著操作次數(shù)的增多Total Size的值會越來越大,直到到達(dá)一個上限后導(dǎo)致進(jìn)程被殺掉。
2.2 MAT分析hprof來定位內(nèi)存泄露的原因所在。
這是出現(xiàn)內(nèi)存泄露后使用MAT進(jìn)行問題定位的有效手段。
A)Dump出內(nèi)存泄露當(dāng)時的內(nèi)存鏡像hprof,分析懷疑泄露的類:
B)分析持有此類對象引用的外部對象
C)分析這些持有引用的對象的GC路徑
D)逐個分析每個對象的GC路徑是否正常
從這個路徑可以看出是一個antiRadiationUtil工具類對象持有了MainActivity的引用導(dǎo)致MainActivity無法釋放。此時就要進(jìn)入代碼分析此時antiRadiationUtil的引用持有是否合理(如果antiRadiationUtil持有了MainActivity的context導(dǎo)致節(jié)目退出后MainActivity無法銷毀,那一般都屬于內(nèi)存泄露了)。
2.3 MAT對比操作前后的hprof來定位內(nèi)存泄露的根因所在。
為查找內(nèi)存泄漏,通常需要兩個 Dump結(jié)果作對比,打開 Navigator History面板,將兩個表的 Histogram結(jié)果都添加到 Compare Basket中去
A) ***個HPROF 文件(usingFile > Open Heap Dump ).
B)打開Histogram view.
C)在NavigationHistory view里 (如果看不到就從Window >show view>MAT- Navigation History ), 右擊histogram然后選擇Add to Compare Basket .
D)打開第二個HPROF 文件然后重做步驟2和3.
E)切換到Compare Basket view, 然后點(diǎn)擊Compare the Results (視圖右上角的紅色"!"圖標(biāo))。
F)分析對比結(jié)果
可以看出兩個hprof的數(shù)據(jù)對象對比結(jié)果。 通過這種方式可以快速定位到操作前后所持有的對象增量,從而進(jìn)一步定位出當(dāng)前操作導(dǎo)致內(nèi)存泄露的具體原因是泄露了什么數(shù)據(jù)對象。
注意:
如果是用 MAT Eclipse 插件獲取的 Dump文件,不需要經(jīng)過轉(zhuǎn)換則可在MAT中打開,Adt會自動進(jìn)行轉(zhuǎn)換。
而手機(jī)SDk Dump 出的文件要經(jīng)過轉(zhuǎn)換才能被 MAT識別,Android SDK提供了這個工具 hprof-conv (位于 sdk/tools下)
首先,要通過控制臺進(jìn)入到你的 android sdk tools 目錄下執(zhí)行以下命令: ./hprof-conv xxx-a.hprof xxx-b.hprof 例如 hprof-conv input.hprof out.hprof 此時才能將out.hprof放在eclipse的MAT中打開。
手機(jī)管家內(nèi)存泄露每日監(jiān)控方案
目前手機(jī)管家的內(nèi)存泄露每日監(jiān)控會自動運(yùn)行并輸出是否存在疑似泄露的報(bào)告郵件,不論泄露對象的大小。這其中涉及的核心技術(shù)主要是AspectJ,MLD自研工具(原理是虛引用)和UIAutomator。
3.1 AspectJ插樁監(jiān)控代碼
手機(jī)管家目前使用一個ant腳本加入MLD的監(jiān)控代碼,并通過AspectJ的語法實(shí)現(xiàn)插樁。 使用AspectJ的原因是可以靈活分離出項(xiàng)目源碼與監(jiān)控代碼,通過不同的編譯腳本打包出不同用途的安裝測試包:如果測試包是經(jīng)過Aspect插樁了MLD監(jiān)控代碼的話,那么運(yùn)行完畢后會輸出指定格式的日志文件,作為后續(xù)分析工作的數(shù)據(jù)基礎(chǔ)。
3.2 MLD實(shí)現(xiàn)監(jiān)控核心邏輯
這是手機(jī)管家內(nèi)的一個工具工程,正式打包不會打入,BVT等每日監(jiān)控測試包可以打入。打入后可以通過諸如addObject接口(通過反射去檢查是否含有該工具并調(diào)用)來加入需要監(jiān)控的檢測對象,這個工具會自動在指定時機(jī)(如退出管家)去檢測該對象是否發(fā)生泄漏。
這個內(nèi)存泄露檢測的基本原理是:
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用(在虛引用函數(shù)就必須關(guān)聯(lián)指定)。當(dāng)垃圾回收器準(zhǔn)備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,自動把這個虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來了解被引用的對象是否將要被垃圾回收。
基于以上原理,MLD工具在調(diào)用接口addObject加入監(jiān)控類型時,會為該類型對象增加一個虛引用,注意虛引用并不會影響該對象被正?;厥铡R虼丝梢栽赗eferenceQueue引用隊(duì)列中統(tǒng)計(jì)未被回收的監(jiān)控對象是否超過指定閥值。
利用PhantomReferences(虛引用)和ReferenceQueue(引用隊(duì)列),當(dāng)PhantomReferences被加入到相關(guān)聯(lián)的ReferenceQueue時,則視該對象已經(jīng)或處于垃圾回收器回收階段了。
MLD監(jiān)控原理核心
目前手機(jī)管家已對大部分類完成內(nèi)存泄露的監(jiān)控,包括各種activity,service和view頁面等,務(wù)求在技術(shù)上能帶給用戶最順滑的產(chǎn)品體驗(yàn)。
接下來簡單介紹下這個工具的判斷核心。根據(jù)虛引用監(jiān)控到的內(nèi)存狀態(tài),需要通過多種策略來判斷是否存在內(nèi)存泄露。
(1)最簡單的方式就是直接在加入監(jiān)控時就為該類型設(shè)定***存在個數(shù),舉個例子,各個DAO對象理論上只能存在最多一個,因此一旦出現(xiàn)兩個相同的DAO,那一般都是泄露了;
(2)第二種情況是在頁面退出程序退出時,檢索gc后無法釋放的對象列表,這些對象類型也會成為內(nèi)存泄露的懷疑對象;
(3)***一種情況比較復(fù)雜,基本原理是根據(jù)歷史操作判斷對象數(shù)量的增長幅度。根據(jù)對象的增長通過最小二乘法擬合出該對象類型的增長速度,如果超過經(jīng)驗(yàn)值則會列入疑似泄露的對象列表。
3.3 UIAutomator完成重復(fù)操作的自動化
***一步就很簡單了。這么多反復(fù)的UI操作,讓人工來點(diǎn)就太浪費(fèi)人力了。我們使用UIAutomator來進(jìn)行自動化操作測試。
目前手機(jī)管家的每日自動化測試已覆蓋各個功能的主路徑,并通過配置文件的方式來靈活驅(qū)動用例的增刪改查,***限度保證了隨著版本推移用例的復(fù)用價值。
至此手機(jī)管家的內(nèi)存泄露測試方案介紹完畢,也歡迎各路牛人交流溝通更多更強(qiáng)的內(nèi)存泄露工具盒方案!
騰訊Bugly簡介
Bugly是騰訊內(nèi)部產(chǎn)品質(zhì)量監(jiān)控平臺的外發(fā)版本,其主要功能是App發(fā)布以后,對用戶側(cè)發(fā)生的Crash以及卡頓現(xiàn)象進(jìn)行監(jiān)控并上報(bào),讓開發(fā)同學(xué)可以***時間了解到App的質(zhì)量情況,及時機(jī)型修改。目前騰訊內(nèi)部所有的產(chǎn)品,均在使用其進(jìn)行線上產(chǎn)品的崩潰監(jiān)控。