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