最近時(shí)間都利用的不太好,都是到下午才開始學(xué)習(xí)或者做事,一上午都吹B或者XXX用掉了。。。不太好,這里督促下自己不要再懶惰,哈哈?。?/p>
再安利下我的整合庫,方便大家找資源:https://github.com/ddwhan0123/Useful-Open-Source-Android
廢話不多說,今天來講下一個(gè)“經(jīng)?!庇龅降囊粋€(gè)內(nèi)存泄露的情況來引出想提的Java的4種引用方式
在舉例子之前先將一些基礎(chǔ)的知識(shí),不然基礎(chǔ)薄弱的同學(xué)還會(huì)不理解什么的。(當(dāng)然,我會(huì)講的很粗略,但是你一定能看懂)
通常Java分配內(nèi)存有三種策略,分別為靜態(tài)存儲(chǔ)區(qū),棧,堆。
靜態(tài)存儲(chǔ)區(qū): 平時(shí)那些static的變量啊,方法啊都在這里面,并且在程序整個(gè)運(yùn)行期間都存在。
棧:我們執(zhí)行的那些方法所產(chǎn)生的對(duì)象都在這里面,方法結(jié)束這些東西就會(huì)被釋放掉。
堆:我們平時(shí) new出來的那些對(duì)象都會(huì)在這里面。
那如何區(qū)分堆,棧呢?
局部變量的基本數(shù)據(jù)類型和引用存儲(chǔ)于棧中,引用的對(duì)象實(shí)體存儲(chǔ)于堆中?!?因?yàn)樗鼈儗儆诜椒ㄖ械淖兞浚芷陔S方法而結(jié)束。
成員變量全部存儲(chǔ)與堆中(包括基本數(shù)據(jù)類型,引用和引用的對(duì)象實(shí)體)—— 因?yàn)樗鼈儗儆陬?,類?duì)象終究是要被new出來使用的。
那接下來我們來看下例子
Handler 造成的內(nèi)存泄漏
為什么會(huì)出現(xiàn)?
Handler 屬于 TLS(Thread Local Storage) 變量, 生命周期和 Activity 是不一致的。所以很有可能我們的Activity的邏輯早就結(jié)束了,但是Handler持有Activity的引用導(dǎo)致Activity的資源無法回收。
可以看下這個(gè)簡單的例子:

myHandler 將其 push 進(jìn)了消息隊(duì)列 MessageQueue 里。
當(dāng)該 Activity 被 finish() 掉時(shí),延遲執(zhí)行任務(wù)的 Message 還會(huì)繼續(xù)存在于主線程中,它持有該 Activity 的 Handler 引用,所以此時(shí) finish() 掉的 Activity 就不會(huì)被回收了
從而造成內(nèi)存泄漏(因 Handler 為非靜態(tài)內(nèi)部類,它會(huì)持有外部類的引用)。
那我們可以在Handler申明的時(shí)候加 static,讓他存活期跟 Activity 的生命周期就無關(guān)了。
然后我又找到了一個(gè)更好的解決方法,就是通過弱引用的方式引入 Activity,避免直接將 Activity 作為 context 傳進(jìn)去。

這樣如果Activity已經(jīng)不在了,也就不做這些事了。
上面已經(jīng)用到了弱飲用,那么和強(qiáng)引用又有什么區(qū)別呢?就是接下來要講的。
java的引用有4種分別是
強(qiáng)引用(StrongReference),軟引用(SoftReference),弱引用(WeakReference),虛引用(PhantomReference)。
強(qiáng)引用是使用最普遍的引用。如果一個(gè)對(duì)象具有強(qiáng)引用,那垃圾回收器絕不會(huì)回收它。
就是我們平時(shí) new 的那些對(duì)象(這里不包括局部變量,別誤解)
像這樣
Apple a=new Apple();
如果是方法內(nèi)的局部變量,在方法結(jié)束前你也不需要做把他設(shè)置為null的操作,讓GC來消除他。顯式地設(shè)置a為null,或超出對(duì)象的生命周期范圍,則gc認(rèn)為該對(duì)象不存在引用,這時(shí)就可以回收這個(gè)對(duì)象
像list之類的因?yàn)?你通常是? List list =new ArrayList<>();出來了的,所以如果不用了,建議手動(dòng)clear()下,而不是以為list.get(x)為null了他就會(huì)被回收。
如果一個(gè)對(duì)象只具有軟引用,則內(nèi)存空間足夠,垃圾回收器就不會(huì)回收它;如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存。
Stringv=newString("wjj");// 強(qiáng)引用
SoftReferencesoftRef=newSoftReference(v);// 軟引用
那么在內(nèi)存吃緊的時(shí)候softRef就會(huì)被回收。
使用場景:
我有一個(gè)Activity,他有很多圖片,圖片都在map里緩存,我切出去再back回來如果不用緩存,每次IO操作去讀sd卡,但是有了緩存我就可以迅速的加載,提升用戶的體驗(yàn)。如果內(nèi)存吃緊被回收了,那也只能去重新加載了(強(qiáng)烈抗議刻意不讓系統(tǒng)回收這些緩存數(shù)據(jù))
在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。
和軟引用的區(qū)別就是,一個(gè)內(nèi)存不足才回收,一個(gè)看到就回收!
用法跟上面幾乎一樣,就不貼代碼了。
應(yīng)用推薦:? 如果這個(gè)對(duì)象是偶爾的使用,并且希望在使用時(shí)隨時(shí)就能獲取到,但又不想影響此對(duì)象的垃圾收集,那么你應(yīng)該用 Weak Reference 來記住此對(duì)象。
如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。
大致的概念如下