今天聊一聊在android開發(fā)中內(nèi)存泄露的那些事。
在開發(fā)中經(jīng)常聽(tīng)人說(shuō)到內(nèi)存泄露和內(nèi)存溢出這兩個(gè)詞語(yǔ)钮科,有些同學(xué)可能還不清楚內(nèi)存泄露和內(nèi)存溢出本質(zhì)上到底有啥區(qū)別。
簡(jiǎn)單的描述一下我對(duì)內(nèi)存泄露和內(nèi)存溢出的理解:
內(nèi)存泄露:你new了一個(gè)對(duì)象,java虛擬機(jī)為這個(gè)對(duì)象在java堆中分配了一塊內(nèi)存,然后這個(gè)對(duì)象你不再使用了拖叙,但是這個(gè)對(duì)象卻沒(méi)有主動(dòng)或者被動(dòng)的被釋放回收。沒(méi)有回收的原因可能是其他對(duì)象引用著這個(gè)對(duì)象赂乐,當(dāng)Java虛擬機(jī)觸發(fā)GC時(shí)憋沿,垃圾收集器檢查到這個(gè)對(duì)象被其他對(duì)象引用著就不會(huì)回收掉這個(gè)對(duì)象,這就造成了內(nèi)存泄露沪猴。
內(nèi)存溢出:當(dāng)你準(zhǔn)備創(chuàng)建一個(gè)比較大的對(duì)象時(shí)而java堆中沒(méi)有足夠大的內(nèi)存來(lái)為這個(gè)對(duì)象分配空間辐啄。這就造成了內(nèi)存溢出。
偶然的一次內(nèi)存泄露不會(huì)對(duì)我們應(yīng)用造成影響运嗜,頻繁的內(nèi)存泄露就會(huì)造成內(nèi)存溢出以至于java虛擬機(jī)拋出 OutOfMemoryError錯(cuò)誤以至于使我們的APP閃退壶辜。
下面我就說(shuō)一下怎么用AndroidStudio來(lái)檢查分析我們的程序有沒(méi)有內(nèi)存泄露。
以我們的app為例担租,在app里選擇一個(gè)課程進(jìn)行播放聽(tīng)課砸民,然后退出播放界面互道主界面,然后反復(fù)進(jìn)行此操作兩次》芫龋現(xiàn)在我們停留在主界面岭参,此時(shí)在Java堆內(nèi)存里應(yīng)該只有主界面這個(gè)activity的實(shí)例,不應(yīng)該有播放界面這個(gè)activity的實(shí)例尝艘。因?yàn)槲覀円呀?jīng)退出了播放界面演侯,這個(gè)界面應(yīng)該被GC回收掉。
我們就來(lái)看下當(dāng)前內(nèi)存里的情況是不是和我們說(shuō)的一樣只有主界面這個(gè)activiy這個(gè)實(shí)例背亥。
首先在Android Monitor下點(diǎn)擊Monitor標(biāo)簽秒际,出現(xiàn)下圖
點(diǎn)擊B圖標(biāo)手動(dòng)觸發(fā)一下GC,然后點(diǎn)擊C圖標(biāo)狡汉,此時(shí)會(huì)生成一個(gè)heap文件娄徊。因?yàn)槲覀円敿?xì)分析內(nèi)存泄露原因,需要借助于MAT插件來(lái)分析盾戴,此時(shí)生成的.hprof文件并不能直接在MAT中打開寄锐,需要轉(zhuǎn)換一下,具體的轉(zhuǎn)換方法請(qǐng)google尖啡。
我們用MAT打開剛才生成的.hprof文件 橄仆,按下圖做如下操作
我們目前只分析activiy中的內(nèi)存泄露所以點(diǎn)擊QQL圖標(biāo) 輸入 select * from instanceof android.app.Activity 點(diǎn)擊紅色感嘆號(hào),結(jié)果如圖所示
我們看到當(dāng)前內(nèi)存里有三個(gè)MyPlayVideoActivity(也就是我們的播放界面)實(shí)例可婶,怎么會(huì)有三個(gè)實(shí)例呢沿癞,我明明已經(jīng)退出這個(gè)界面回到主界面了怎么會(huì)沒(méi)有被回收呢援雇。
對(duì)因?yàn)閮?nèi)存泄露了所以沒(méi)有回收矛渴。
我們來(lái)看下為什么會(huì)沒(méi)有被回收呢,右擊MyPlayVideoActity如圖操作
下圖我們具體看下到底誰(shuí)在引用著MyPlayVideoActivity以至于不能回收
從圖中我們看到是一個(gè)內(nèi)部類TimerTask在搞鬼,他們的GC鏈為Timer→MediaController→BaseSharkPlayVdieoActivity
我們知道了是因?yàn)檫@個(gè)Timer內(nèi)部類一直持有MyPlayVideoActivity的引用以至于MyPlayVideoActivity不能被回收從而造成了內(nèi)存泄露具温。
既然找到了原因解決掉這個(gè)內(nèi)部類不讓它在持有MyPlayVideoActivity的引用蚕涤,自然就不會(huì)出現(xiàn)內(nèi)存泄露的原因了。
推薦一個(gè)工具leakcanary能很好的定位內(nèi)存泄露铣猩,如果你想詳細(xì)的分析內(nèi)存泄露還是使用強(qiáng)大的MAT來(lái)分析揖铜。