銜接上篇:
新年過(guò)后獻(xiàn)上關(guān)于Android內(nèi)存泄漏的種種總結(jié)
(順手留下GitHub鏈接,需要獲取相關(guān)面試等內(nèi)容的可以自己去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)
在Android應(yīng)用的開(kāi)發(fā)中,為了防止內(nèi)存溢出,在處理一些占用內(nèi)存大而且聲明周 期較長(zhǎng)的對(duì)象時(shí)候,可以盡量應(yīng)用軟引用和弱引用技術(shù)。
軟/弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用 的對(duì)象被垃圾回收器回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì) 列中。利用這個(gè)隊(duì)列可以得知被回收的軟/弱引用的對(duì)象列表,從而為緩沖器清除已 失效的軟/弱引用。
假設(shè)我們的應(yīng)用會(huì)用到大量的默認(rèn)圖片,比如應(yīng)用中有默認(rèn)的頭像,默認(rèn)游戲圖標(biāo) 等等,這些圖片很多地方會(huì)用到。如果每次都去讀取圖片,由于讀取文件需要硬件 操作,速度較慢,會(huì)導(dǎo)致性能較低。所以我們考慮將圖片緩存起來(lái),需要的時(shí)候直 接從內(nèi)存中讀取。但是,由于圖片占用內(nèi)存空間比較大,緩存很多圖片需要很多的 內(nèi)存,就可能比較容易發(fā)生OutOfMemory異常。這時(shí),我們可以考慮使用軟/弱引 用技術(shù)來(lái)避免這個(gè)問(wèn)題發(fā)生。
以下就是高速緩沖器的雛形: 首先定義一個(gè)HashMap,保存軟引用對(duì)象。
private Map > imageCache = new Has
hMap > ();
再來(lái)定義一個(gè)方法,保存Bitmap的軟引用到HashMap
。
使用軟引用以后,在OutOfMemory異常發(fā)生之前,這些緩存的圖片資源的內(nèi)存空間 可以被釋放掉的,從而避免內(nèi)存達(dá)到上限,避免Crash發(fā)生。 如果只是想避免OutOfMemory異常的發(fā)生,則可以使用軟引用。
如果對(duì)于應(yīng)用的性 能更在意,想盡快回收一些占用內(nèi)存比較大的對(duì)象,則可以使用弱引用。
另外可以根據(jù)對(duì)象是否經(jīng)常使用來(lái)判斷選擇軟引用還是弱引用。如果該對(duì)象可能會(huì) 經(jīng)常使用的,就盡量用軟引用。如果該對(duì)象不被使用的可能性更大些,就可以用弱 引用
ok,繼續(xù)回到主題。前面所說(shuō)的,創(chuàng)建一個(gè)靜態(tài)Handler內(nèi)部類(lèi),然后對(duì) Handler 持有的對(duì)象使用弱引用,這樣在回收時(shí)也可以回收 Handler 持有的對(duì)象,但是這樣 做雖然避免了 Activity 泄漏,不過(guò) Looper
線程的消息隊(duì)列中還是可能會(huì)有待處理的 消息,所以我們?cè)?Activity 的 Destroy 時(shí)或者 Stop 時(shí)應(yīng)該移除消息隊(duì)列 MessageQueue
中的消息。
下面幾個(gè)方法都可以移除 Message:
public final void removeCallbacks(Runnable r);
public final void removeCallbacks(Runnable r, Object token);
public final void removeCallbacksAndMessages(Object token);
public final void removeMessages(int what);
public final void removeMessages(int what, Object object);
盡量避免使用 static 成員變量
如果成員變量被聲明為 static,那我們都知道其生命周期將與整個(gè)app進(jìn)程生命 周期一樣。
這會(huì)導(dǎo)致一系列問(wèn)題,如果你的app進(jìn)程設(shè)計(jì)上是長(zhǎng)駐內(nèi)存的,那即使app切到 后臺(tái),這部分內(nèi)存也不會(huì)被釋放。按照現(xiàn)在手機(jī)app內(nèi)存管理機(jī)制,占內(nèi)存較 大的后臺(tái)進(jìn)程將優(yōu)先回收,因?yàn)槿绻薬pp做過(guò)進(jìn)程互保?;睿菚?huì)造成app在 后臺(tái)頻繁重啟。當(dāng)手機(jī)安裝了你參與開(kāi)發(fā)的app以后一夜時(shí)間手機(jī)被消耗空了 電量、流量,你的app不得不被用戶卸載或者靜默。 這里修復(fù)的方法是:
不要在類(lèi)初始時(shí)初始化靜態(tài)成員??梢钥紤]lazy初始化。 架構(gòu)設(shè)計(jì)上要思考是否真 的有必要這樣做,盡量避免。如果架構(gòu)需要這么設(shè)計(jì),那么此對(duì)象的生命周期你有 責(zé)任管理起來(lái)。
override finalize()
2、finalize 方法只會(huì)被執(zhí)行一次,即使對(duì)象被復(fù)活,如果已經(jīng)執(zhí)行過(guò)了 finalize 方法,再次被 GC 時(shí)也不會(huì)再執(zhí)行了,原因是:
含有 finalize
方法的 object 是在 new 的時(shí)候由虛擬機(jī)生成了一個(gè) finalize reference
在來(lái)引用到該Object的,而在 finalize 方法執(zhí)行的時(shí)候,該 object 所 對(duì)應(yīng)的 finalize Reference
會(huì)被釋放掉,即使在這個(gè)時(shí)候把該 object 復(fù)活(即用 強(qiáng)引用引用住該 object ),再第二次被 GC 的時(shí)候由于沒(méi)有了 finalize reference
與之對(duì)應(yīng),所以 finalize 方法不會(huì)再執(zhí)行。
3、含有Finalize方法的object需要至少經(jīng)過(guò)兩輪GC才有可能被釋放。
BraodcastReceiver
,ContentObserver
,F(xiàn)ile,游標(biāo) Cursor, Stream,Bitmap等資源的使用,應(yīng)該在Activity銷(xiāo)毀時(shí)及時(shí)關(guān)閉或者注銷(xiāo),否 則這些資源將不會(huì)被回收,造成內(nèi)存泄漏。比如:
構(gòu)造 Adapter 時(shí),沒(méi)有使用緩存的 convertView
,每次都在創(chuàng)建新的 converView
。這里推薦使用 ViewHolder
。
getApplicationContext
或者 getApplication
,以避免 Activity 被外部長(zhǎng) 生命周期的對(duì)象引用而泄露。Activity onStop
或者 onDestroy
的時(shí)候,取消掉該 Handler
對(duì)象的 Message
和 Runnable
.BraodcastReceiver
,ContentObserver
,F(xiàn)ile,游 標(biāo) Cursor,Stream,Bitmap等資源的使用,應(yīng)該在Activity銷(xiāo)毀時(shí)及時(shí)關(guān)閉或 者注銷(xiāo)。刪減了一部分,見(jiàn)諒^_^
(順手留下GitHub鏈接,需要獲取相關(guān)面試等內(nèi)容的可以自己去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。