最初看到了這篇文章十分鐘理解Java中的弱引用 ,讓我有想法嘗試去理解java.lang.ref.WeakReference類的弱引用垦搬。首先抱歉對該篇文章會有過多引用的地方呼寸。
一。什么是引用
實際上猴贰,Java中存在四種引用对雪,它們由強到弱依次是:強引用、軟引用米绕、弱引用瑟捣、虛引用。下面我們簡單介紹下除弱引用外的其他三種引用:
強引用(Strong Reference):通常我們通過new來創(chuàng)建一個新對象時返回的引用就是一個強引用栅干,若一個對象通過一系列強引用可到達迈套,它就是強可達的(strongly reachable),那么它就不被回收
軟引用(Soft Reference):軟引用和弱引用的區(qū)別在于碱鳞,若一個對象是弱引用可達桑李,無論當前內存是否充足它都會被回收,而軟引用可達的對象在內存不充足時才會被回收窿给,因此軟引用要比弱引用“強”一些
虛引用(Phantom Reference):虛引用是Java中最弱的引用贵白,那么它弱到什么程度呢?它是如此脆弱以至于我們通過虛引用甚至無法獲取到被引用的對象崩泡,虛引用存在的唯一作用就是當它指向的對象被回收后禁荒,虛引用本身會被加入到引用隊列中,用作記錄它指向的對象已被銷毀角撞。
弱引用:
弱引用對象的存在不會阻止它所指向的對象變被垃圾回收器回收呛伴。弱引用最常見的用途是實現規(guī)范映射(canonicalizing mappings,比如哈希表)谒所。假設垃圾收集器在某個時間點決定一個對象是弱可達的(weakly reachable)(也就是說當前指向它的全都是弱引用)热康,這時垃圾收集器會清除所有指向該對象的弱引用,然后垃圾收集器會把這個弱可達對象標記為可終結(finalizable)的百炬,這樣它們隨后就會被回收褐隆。與此同時或稍后,垃圾收集器會把那些剛清除的弱引用放入創(chuàng)建弱引用對象時所登記到的引用隊列(Reference Queue)中剖踊。
引用隊列:
WeakReference類有兩個構造函數:
WeakReference(T referent)//創(chuàng)建一個指向給定對象的弱引用
WeakReference(T referent, ReferenceQueue q)//創(chuàng)建一個指向給定對象并且登記到給定引用隊列的弱引用
我們可以看到第二個構造方法中提供了一個ReferenceQueue類型的參數庶弃,通過提供這個參數,我們便把創(chuàng)建的弱引用對象注冊到了一個引用隊列上德澈,這樣當它被垃圾回收器清除時歇攻,就會把它送入這個引用隊列中,我們便可以對這些被清除的弱引用對象進行統(tǒng)一管理梆造。
二缴守。使用弱引用
首先我把文章作者提出的場景拿過來用:
現在有一個Product類代表一種產品葬毫,這個類被設計為不可擴展的,而此時我們想要為每個產品增加一個編號屡穗。一種解決方案是使用HashMap<Product,Integer>,于是問題來了贴捡,如果我們已經不再需要一個Product對象存在于內存中(比如已經賣出了這件產品),假設指向它的引用為productA村砂,我們這時會給productA賦值為null烂斋,然而這時productA過去指向的Product對象并不會被回收,因為它顯然還被HashMap引用著础废。所以這種情況下汛骂,我們想要真正的回收一個Product對象,僅僅把它的強引用賦值為null是不夠的评腺,還要把相應的條目從HashMap中移除帘瞭。顯然“從HashMap中移除不再需要的條目”這個工作我們不想自己完成,我們希望告訴垃圾收集器:“在只有HashMap中的key在引用著Product對象的情況下蒿讥,就可以回收相應Product對象了蝶念。”
那該如何解決上述問題诈悍?我們就會考慮用弱引用概念來解決上述問題祸轮,我們會把hashmap的key由product換為WeakReference<Product>:
本來:
Hashmap<Product ,Integer> hashmap = new Hashmap<>();
Product productA ;
for(int i=0;i<10;i++){
?Product product = new Product();//這句話表明product指向Product對象
if(i=0) productA = product;
hashmap.put(product,i);
}
當把productA = null時兽埃,并不能把hashmap對應的product回收侥钳。
當改為:
Hashmap hashmap = new Hashmap<>();
WeakReference<Product> weakProductA ;
for(int i=0;i<10;i++){
Product product = new Product();
WeakReference<Product> weakProduct =new WeakReference<>(product);
if(i=0) weakProductA= weakProduct;
hashmap.put(product,i);
}
現在,弱引用對象weakProductA就指向了Product對象productA柄错。那么我們怎么通過weakProduct獲取它所指向的Product對象productA呢舷夺?很簡單,只需要下面這句代碼:
Product product = weakProductA.get()售貌;
當我們把product=null時给猾,表明它所引用的Product已經無需存在于內存中,這時指向這個Product對象的就是由弱引用對象weakProductA了颂跨,那么顯然這時候相應的Product對象時弱可達的敢伸,所以指向它的弱引用會被清除,這個Product對象隨即會被回收恒削,指向它的弱引用對象會進入引用隊列中池颈。
其實對于上述問題,java本身提供了WeakHashMap類钓丰,使用和這個類躯砰,它的鍵自然就是弱引用對象,無需我們再手動包裝原始對象携丁。
三琢歇。使用弱引用
只要某個對象有強引用與之關聯(lián),JVM必定不會回收這個對象,即使在內存不足的情況下李茫,JVM寧愿拋出OutOfMemory錯誤也不會回收這種對象揭保。所以回歸到android本身,最容易引起android系統(tǒng)OOM的最大問題就是bitmap問題魄宏,因為bitmap本身所占內存就很大掖举,處理不得當,系統(tǒng)就會OOM娜庇,發(fā)生崩潰塔次。為了保證系統(tǒng)不因bitmap發(fā)生OOM,我們考慮用軟引用:
Java中的SoftReference即對象的軟引用名秀。如果一個對象具有軟引用励负,內存空間足夠,垃圾回收器就不會回收它匕得;如果內存空間不足了继榆,就會回收這些對象的內存。只要垃圾回收器沒有回收它汁掠,該對象就可以被程序使用略吨。軟引用可用來實現內存敏感的高速緩存。使用軟引用能防止內存泄露考阱,增強程序的健壯性翠忠。
下面有一個這樣的應用場景:我們通過圖片本地路徑,可以索引到我們之前通過正常手段獲取對應的bitmap乞榨。
本來:
Hashmap<String,Bitmap> hashmap = new Hashmap<>();
public Bitmap getBmByPath(String path){
???? Bitmap bitmap = hashmap.get(path)
? ? ? if(bitmap!=null){
? ? ? ? ? ? return bitmap;
????? }else{
? ? ? ????? bitmap= getBitmapFromPath(path);
??????????? hashmap.put(path,bitmap);
??????????? return bitmap;
???? }
}
這樣設計導致系統(tǒng)內存不足時秽之,也不會主動回收存儲的bitmap。
所以改進為:
Hashmap<String,SoftReference<Bitmap>> hashmap = new Hashmap<>();
public Bitmap getBmByPath(String path){
???? SoftReference<Bitmap> softbitmap = hashmap.get(path)
???? if(softbitmap.get()!=null){
?????? return softbitmap.get();
??? }else{
????? bitmap= getBitmapFromPath(path);
????? SoftReference<Bitmap> d =new SoftReference<>(bitmap);
????? hashmap.put(path,d);
????? return bitmap;
??? }
}
總結:文章上面我寫了兩個引用吃既,一個是弱引用考榨,一個軟應用,為什么不同應用場景我選擇不同的引用鹦倚。我給大家分析一下河质,在我需要主動回收某對象時,希望它引用的那些對象也會被回收震叙,那我會選擇用軟引用掀鹅。當我需要在系統(tǒng)內存不足時,希望系統(tǒng)主動回收某對象時捐友,我會用弱引用淫半。