基于Android Studio的內(nèi)存泄漏檢測(cè)與解決全攻略

轉(zhuǎn)載 http://wetest.qq.com/lab/view/?id=99

自從Google在2013年發(fā)布了Android Studio后,Android Studio憑借著自己良好的內(nèi)存優(yōu)化,酷炫的UI主題,強(qiáng)大的自動(dòng)補(bǔ)全提示以及Gradle的編譯支持正逐步取代Eclipse,成為主流的Android開(kāi)發(fā)IDE。Android Studio在為我們提供了良好的編碼體驗(yàn)的同時(shí),也提供了許多對(duì)App性能分析的工具,讓開(kāi)發(fā)者可以更方便分析App性能。Google在IO大會(huì)上一直告誡開(kāi)發(fā)者不要無(wú)節(jié)制的使用手機(jī)內(nèi)存,要注意一些不良的開(kāi)發(fā)習(xí)慣會(huì)導(dǎo)致App的內(nèi)存泄漏。雖然如今網(wǎng)上檢測(cè)App內(nèi)存泄漏的文章汗牛充棟,但是要使用DDMS和MAT,不僅使用步驟復(fù)雜繁瑣,而且要手動(dòng)排查內(nèi)存泄漏的位置,操作起來(lái)多有不便。其實(shí)Android Studio已經(jīng)開(kāi)始支持自動(dòng)進(jìn)行內(nèi)存泄漏檢查了,本文就帶著大家一探其中的奧妙吧。

什么是內(nèi)存泄漏

Android虛擬機(jī)的垃圾回收采用的是根搜索算法。GC會(huì)從根節(jié)點(diǎn)(GC Roots)開(kāi)始對(duì)heap進(jìn)行遍歷。到最后,部分沒(méi)有直接或者間接引用到GC Roots的就是需要回收的垃圾,會(huì)被GC回收掉。而內(nèi)存泄漏出現(xiàn)的原因就是存在了無(wú)效的引用,導(dǎo)致本來(lái)需要被GC的對(duì)象沒(méi)有被回收掉。

舉個(gè)栗子

privatestaticLeak mLeak;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);? ? ? ? setContentView(R.layout.activity_second);? ? ? ? mLeak =newLeak();? ? }classLeak{? ? }

mLeak是存儲(chǔ)在靜態(tài)區(qū)的靜態(tài)變量,而Leak是內(nèi)部類(lèi),其持有外部類(lèi)Activity的引用。這樣就導(dǎo)致Activity需要被銷(xiāo)毀時(shí),由于被mLeak所持有,所以系統(tǒng)不會(huì)對(duì)其進(jìn)行GC,這樣就造成了內(nèi)存泄漏。

再舉一個(gè)最常犯的栗子

publicclassSingleton{privatestaticSingleton instance;privateContext mContext;privateSingleton(Context context){this.mContext = context;? ? }publicstaticSingletongetInstance(Context context){if(instance ==null){synchronized(Singleton.class){if(instance ==null){? ? ? ? ? ? ? ? ? ? instance =newSingleton(context);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }returninstance;? ? }}

如果我們?cè)谠谡{(diào)用Singleton的getInstance()方法時(shí)傳入了Activity。那么當(dāng)instance沒(méi)有釋放時(shí),這個(gè)Activity會(huì)一直存在。因此造成內(nèi)存泄露。

解決方法可以將new Singleton(context)改為new Singleton(context.getApplicationContext())即可,這樣便和傳入的Activity沒(méi)關(guān)系了。

內(nèi)存泄漏的檢測(cè)

打開(kāi)Android Studio,編譯代碼,在模擬器或者真機(jī)上運(yùn)行App,然后點(diǎn)擊

,在Android Monitor下點(diǎn)擊Monitor對(duì)應(yīng)的Tab,進(jìn)入如下界面

在Memory一欄中,可以觀察不同時(shí)間App內(nèi)存的動(dòng)態(tài)使用情況,點(diǎn)擊

可以手動(dòng)觸發(fā)GC,點(diǎn)擊

可以進(jìn)入HPROF Viewer界面,查看Java的Heap,如下圖

Reference Tree代表指向該實(shí)例的引用,可以從這里面查看內(nèi)存泄漏的原因,Shallow Size指的是該對(duì)象本身占用內(nèi)存的大小,Retained Size代表該對(duì)象被釋放后,垃圾回收器能回收的內(nèi)存總和。

下面我們以掌上道聚城客戶(hù)端為例,來(lái)一探內(nèi)存泄漏檢測(cè)的方法。

打開(kāi)Android Studio,編譯代碼,運(yùn)行掌上道聚城,然后開(kāi)始盡情的耍我們的App啦,然后就從Memory Monitor里面觀察App的內(nèi)存使用曲線,突然發(fā)現(xiàn),納尼!??!怎么內(nèi)存使用越來(lái)越大了,這就很有可能是發(fā)生內(nèi)存泄漏了,然后點(diǎn)擊

手動(dòng)進(jìn)行GC,再點(diǎn)擊

觀看JavaHeap,點(diǎn)擊Analyzer Task,Android Monitor就可以為我們自動(dòng)分析泄漏的Activity啦,分析出來(lái)如下圖所示

在Reference Tree里面,我們直接就可以看到持有該Activity的單例對(duì)象,直接定位到該單例中的代碼,發(fā)現(xiàn)代碼中出現(xiàn)了

publicstaticVideoTagHelpergetInstance(Context context){if(tagHelper ==null) {? ? ? ? ? ? tagHelper =newVideoTagHelper();? ? ? ? }? ? ? ? tagHelper.context = context;returntagHelper;? ? }

和剛剛舉得栗子里出現(xiàn)的錯(cuò)誤一模一樣啊,這段代碼是誰(shuí)寫(xiě)的,拖出去······

我們修復(fù)了檢查出的內(nèi)存泄漏的問(wèn)題,并將修復(fù)前和修復(fù)后的代碼在相同的模擬器上運(yùn)行并進(jìn)行相同的操作,查看他們使用內(nèi)存的情況,如下圖所示

有內(nèi)存泄漏的情況,占用內(nèi)存約為43M

修復(fù)了內(nèi)存泄漏問(wèn)題,占用內(nèi)存為36M

在修復(fù)了內(nèi)存泄漏問(wèn)題后,內(nèi)存使用下降了16.3%?。?!

掌握了Android Monitor的使用方法后,媽媽再也不擔(dān)心我寫(xiě)的App會(huì)出現(xiàn)內(nèi)存泄漏啦?。。?/p>

最后編輯于
?著作權(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)容