常見案例
handler耗時引發(fā)的內(nèi)存泄漏
當(dāng)activity當(dāng)中存在handler接收耗時的消息時,比如我們一般在網(wǎng)絡(luò)請求切換線程時咕娄,經(jīng)常使用到handler,假設(shè)消息還沒有發(fā)送完成珊擂,但是頁面已經(jīng)被關(guān)閉圣勒,也就說activity已經(jīng)執(zhí)行了ondestroy方法。當(dāng)gc回收時摧扇,會出現(xiàn)該activity不能被回收的情況圣贸,導(dǎo)致內(nèi)存泄漏。
解決辦法:當(dāng)activity銷毀的時候扛稽,調(diào)用handler的removeCallbacksAndMessages方法吁峻,移除消息任務(wù),然后將handler對象及線程置空。
內(nèi)部類引發(fā)的內(nèi)存泄漏(當(dāng)然handler或子線程一般也作為內(nèi)部類使用)
因?yàn)閖ava當(dāng)中用含,內(nèi)部類默認(rèn)持有外部類的引用矮慕,當(dāng)外部類銷毀后,一旦gc回收該實(shí)例耕餐,發(fā)現(xiàn)內(nèi)部類持有他的引用而導(dǎo)致不能回收該實(shí)例凡傅,出現(xiàn)內(nèi)存泄漏的情況。
解決方法:將內(nèi)部類改為靜態(tài)內(nèi)部類肠缔,因?yàn)殪o態(tài)內(nèi)部類生命周期和應(yīng)用一樣長夏跷,所以當(dāng)退出程序的時候會一同回收該實(shí)例,并不會影響外部類的回收明未。
單例導(dǎo)致的內(nèi)存泄漏
因?yàn)樵谑褂脝卫臅r候槽华,經(jīng)常會傳入一個本類的上下文對象,而單例是靜態(tài)的趟妥,生命周期和application一樣長猫态,當(dāng)activity銷毀的時候,該單例持有activity的引用導(dǎo)致其不能被回收披摄,出現(xiàn)內(nèi)存泄漏亲雪。
解決方法:在使用上下文的時候,傳全局上下文疚膊。
資源未關(guān)閉
Cursor义辕,stream,database寓盗,Butterknife灌砖,broadcastreciver,bindservice傀蚌,eventBus
比如這些東西在使用完成后基显,需要進(jìn)行close或者Unbind處理,以節(jié)省內(nèi)存
Bitmap對象不在使用時調(diào)用recycle()釋放內(nèi)存
Timer計時器善炫、動畫撩幽,因?yàn)檫@些涉及耗時問題,如果activity銷毀销部,而該任務(wù)并未執(zhí)行完成摸航,會導(dǎo)致內(nèi)存泄漏,所以一般在activity中如果使用到這些耗時任務(wù)舅桩,需要在activity銷毀時酱虎,做對應(yīng)處理,比如調(diào)用timer的cancel方法擂涛,或者動畫的cancel方法并將對象置空
一些監(jiān)聽器的內(nèi)存泄漏读串,比如說我們給edittext設(shè)置輸入文字監(jiān)聽時聊记,當(dāng)監(jiān)聽到文字發(fā)生變化,我們通過獲取變化后的文字執(zhí)行了耗時任務(wù)(比如獲取到edittext里的內(nèi)容上傳服務(wù)器)恢暖,當(dāng)耗時任務(wù)未執(zhí)行完成activity銷毀了排监,會引發(fā)內(nèi)存泄漏,所以在onDestory時杰捂,取消注冊舆床,比如說editText調(diào)用removeTextChangedListener方法
Rxjava的內(nèi)存泄漏:因?yàn)閞xjava采用的是觀察者模式,當(dāng)請求到數(shù)據(jù)后會根據(jù)訂閱關(guān)系將數(shù)據(jù)發(fā)送個訂閱者嫁佳,而如果這時訂閱者已經(jīng)銷毀挨队,就會出現(xiàn)引用該對象導(dǎo)致其不能被回收的情況,出現(xiàn)內(nèi)存泄漏蒿往,rxjava2發(fā)布的時候也發(fā)現(xiàn)了這個問題盛垦,所以在回調(diào)當(dāng)中,新增加了onSubcribe回調(diào)瓤漏,同時返回了一個disposable對象腾夯,可以通過判斷disposable里的isDisposed來確定當(dāng)前的訂閱關(guān)系,如果訂閱關(guān)系中的訂閱者已經(jīng)不存在且當(dāng)前訂閱關(guān)系存在蔬充,解除訂閱關(guān)系蝶俱,并終止數(shù)據(jù)的發(fā)送。
webView引發(fā)的內(nèi)存泄漏:因?yàn)閣ebview在使用的時候一般持有activity的引用饥漫,我們一般在activity的onDestroy方法中調(diào)用mWebView.destroy();來釋放webview跷乐。如果在onDetachedFromWindow之前調(diào)用了destroy那就肯定會無法正常反注冊了,也就會導(dǎo)致內(nèi)存泄漏趾浅。所以在銷毀webview前一定要先在onDetachedFromWindow中將webview從它的父view中移除,再調(diào)用destroy方法中調(diào)用webview的destroy馒稍,我開發(fā)的時候在5.1以上的手機(jī)上發(fā)現(xiàn)這種問題比較多皿哨,因?yàn)楝F(xiàn)在5.1以下適配的比較少了,基本沒咋注意纽谒。
線程導(dǎo)致的內(nèi)存泄漏:一般使用子線程都會創(chuàng)建一個內(nèi)部類對象证膨,而創(chuàng)建線程一般執(zhí)行耗時任務(wù),所以這個內(nèi)部類默認(rèn)持有外部類的引用鼓黔,如果耗時任務(wù)在activity銷毀的時候未執(zhí)行完成央勒,會因?yàn)槌钟型獠款愐脤?dǎo)致外部類不能被回收
MVP內(nèi)存泄漏
內(nèi)存抖動:
定義:內(nèi)存抖動是由于短時間內(nèi)有大量對象創(chuàng)建和銷毀,它伴隨著頻繁的GC澳化。
gc會頻繁搶占cup資源崔步,影響UI線程執(zhí)行,會導(dǎo)致app整體卡頓
解決方案:
盡量避免在循環(huán)體內(nèi)創(chuàng)建對象缎谷,應(yīng)該把對象創(chuàng)建移到循環(huán)體外井濒。
注意自定義View的onDraw()方法會被頻繁調(diào)用,所以在這里面不應(yīng)該頻繁的創(chuàng)建對象。
當(dāng)需要大量使用Bitmap的時候瑞你,試著把它們緩存在數(shù)組中實(shí)現(xiàn)復(fù)用酪惭。
對于能夠復(fù)用的對象,同理可以使用對象池將它們緩存起來者甲。