一复旬、定義
內(nèi)存泄漏是指:應(yīng)該被GC回收的對象無法被回收垦缅,這個對象會引發(fā)內(nèi)存泄漏。
二驹碍、危害
1壁涎、引發(fā)內(nèi)存溢出;
2志秃、導(dǎo)致內(nèi)存不足怔球,頻繁觸發(fā)GC,因而導(dǎo)致UI卡頓浮还;
三竟坛、檢測工具
1、MAT(Memory Analyzer Tools)是一個分析Java堆數(shù)據(jù)的專業(yè)工具钧舌,用它可以定位內(nèi)存泄漏的原因担汤。
MAT 使用方法:
內(nèi)存泄漏 之 MAT工具的使用
2、LeakCanary是一個開源的在debug版本中檢測內(nèi)存泄漏的java庫洼冻。
LeakCanary使用方法:
LeakCanary——直白的展現(xiàn)Android中的內(nèi)存泄露
四崭歧、常見案例和解決方案
1、單例中不合理的持有
單例中的對象生命周期與應(yīng)用一致
解決方案:
- 將該屬性的引用方式改為弱引用;
- 如果傳入Context撞牢,使用ApplicationContext;
2率碾、非靜態(tài)內(nèi)部類和匿名類
在Java中,非靜態(tài)內(nèi)部類 和 匿名類 都會潛在的引用它們所屬的外部類屋彪,但是所宰,靜態(tài)內(nèi)部類卻不會。如果這個非靜態(tài)內(nèi)部類實例做了一些耗時的操作畜挥,就會造成外圍對象不會被回收仔粥,從而導(dǎo)致內(nèi)存泄漏。
解決方案:
- 將內(nèi)部類改為靜態(tài)內(nèi)部類;
- 如果有強引用Activity中的屬性砰嘁,則將該屬性的引用方式改為弱引用;
- 在業(yè)務(wù)允許的情況下件炉,當(dāng)Activity執(zhí)行onDestory時,結(jié)束這些耗時任務(wù);
3矮湘、Context的不正確使用
在Android應(yīng)用程序中通痴迕幔可以使用兩種Context對象:Activity Context和Application Context。當(dāng)Activity Context被傳遞到其他實例中缅阳,這可能導(dǎo)致自身被引用而發(fā)生泄漏磕蛇。
解決方案:
- 對于大部分非必須使用Activity Context的情況,應(yīng)該使用Application Context(因為Application Context會隨著應(yīng)用程序的存在而存在十办,而不依賴于activity的生命周期);
- 對Context的引用不要超過它本身的生命周期秀撇,慎重的對Context使用“static”關(guān)鍵字;
- Context里如果有線程向族,一定要在onDestroy()里及時停掉;
4呵燕、Handler引起的內(nèi)存泄漏
當(dāng)Handler中有延遲的的任務(wù)或是等待執(zhí)行的任務(wù)隊列過長,由于消息持有對Handler的引用件相,而Handler又持有對其外部類的潛在引用再扭,這條引用關(guān)系會一直保持到消息得到處理,而導(dǎo)致了Activity無法被垃圾回收器回收夜矗,而導(dǎo)致了內(nèi)存泄露泛范。
解決方案:
- 可以把Handler類放在單獨的類文件中,或者使用靜態(tài)內(nèi)部類便可以避免泄露;
- 如果想在Handler內(nèi)部去調(diào)用所在的Activity,那么可以在handler內(nèi)部使用弱引用的方式去指向所在Activity(使用Static + WeakReference的方式來達到斷開Handler與Activity之間存在引用關(guān)系的目的);
5紊撕、沒有注銷監(jiān)聽器
如果Context 對象想要在服務(wù)內(nèi)部的事件發(fā)生時被通知罢荡,那就需要把自己注冊到服務(wù)的監(jiān)聽器中。然而对扶,這會讓服務(wù)持有Activity 的引用区赵,如果在Activity onDestory時沒有釋放掉引用就會內(nèi)存泄漏。
解決方案:
- 使用Application Context代替Activity Context;
- 在Activity執(zhí)行onDestory時辩稽,調(diào)用反注冊;
6惧笛、資源對象沒有關(guān)閉
資源性對象比如(Cursor,F(xiàn)ile文件等)往往都用了一些緩沖逞泄,我們在不使用的時候患整,應(yīng)該及時關(guān)閉它們,以便它們的緩沖及時回收內(nèi)存喷众。它們的緩沖不僅存在于 java虛擬機內(nèi)各谚,還存在于java虛擬機外。如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們到千,往往會造成內(nèi)存泄漏昌渤。
解決方案:
- 程序退出時確保資源性對象已關(guān)閉;
7、集合中對象沒清理
我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中憔四,當(dāng)我們不需要該對象時膀息,并沒有把它的引用從集合中清理掉般眉,這樣這個集合就會越來越大,可能會導(dǎo)致內(nèi)存泄漏潜支。如果這個集合是static的話甸赃,那情況就更嚴(yán)重了。
解決方案:
- 在Activity退出之前冗酿,將集合里的東西clear埠对,然后置為null,再退出程序裁替;
8项玛、WebView對象沒有回收
不再使用WebView對象時,應(yīng)該調(diào)用它的destory()函數(shù)來銷毀它弱判,并釋放其占用的內(nèi)存襟沮,否則其占用的內(nèi)存長期也不能被回收,從而造成內(nèi)存泄露裕循。
解決方案:
- 為webView開啟另外一個進程臣嚣,通過AIDL與主線程進行通信,WebView所在的進程可以根據(jù)業(yè)務(wù)的需要選擇合適的時機進行銷毀剥哑,從而達到內(nèi)存的完整釋放
9硅则、構(gòu)造Adapter時,沒有使用緩存的ConvertView
初始時ListView會從Adapter中根據(jù)當(dāng)前的屏幕布局實例化一定數(shù)量的View對象株婴,同時ListView會將這些View對象 緩存起來怎虫。
當(dāng)向上滾動ListView時,原先位于最上面的List Item的View對象會被回收困介,然后被用來構(gòu)造新出現(xiàn)的最下面的List Item大审。
這個構(gòu)造過程就是由getView()方法完成的,getView()的第二個形參View ConvertView就是被緩存起來的List Item的View對象(初始化時緩存中沒有View對象則ConvertView是null)座哩。