小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java基礎(chǔ) 之軟引用、弱引用、虛引用 ·[轉(zhuǎn)載]

 SheldonDemo 2017-05-02

2011-11-24 14:43:41
Java基礎(chǔ) 之軟引用、弱引用、虛引用
瀏覽(509)|評(píng)論(1)   交流分類:Java|筆記分類: Java

1、概述

   在JDK1.2以前的版本中,當(dāng)一個(gè)對(duì)象不被任何變量引用,那么程序就無(wú)法再使用這個(gè)對(duì)象。也就是說(shuō),只有對(duì)象處于可觸及狀態(tài),程序才能使用它。這 就像在日常生活中,從商店購(gòu)買了某樣物品后,如果有用,就一直保留它,否則就把它扔到垃圾箱,由清潔工人收走。一般說(shuō)來(lái),如果物品已經(jīng)被扔到垃圾箱,想再 把它撿回來(lái)使用就不可能了。
   但有時(shí)候情況并不這么簡(jiǎn)單,你可能會(huì)遇到類似雞肋一樣的物品,食之無(wú)味,棄之可惜。這種物品現(xiàn)在已經(jīng)無(wú)用了,保留它會(huì)占空間,但是立刻扔掉它也不劃算,因 為也許將來(lái)還會(huì)派用場(chǎng)。對(duì)于這樣的可有可無(wú)的物品,一種折衷的處理辦法是:如果家里空間足夠,就先把它保留在家里,如果家里空間不夠,即使把家里所有的垃 圾清除,還是無(wú)法容納那些必不可少的生活用品,那么再扔掉這些可有可無(wú)的物品。
   從JDK1.2版本開(kāi)始,把對(duì)象的引用分為四種級(jí)別,從而使程序能更加靈活的控制對(duì)象的生命周期。這四種級(jí)別由高到低依次為:強(qiáng)引用、軟引用、弱引用和虛引用。

下圖為對(duì)象層次的引用

2、強(qiáng)引用
   平時(shí)我們編程的時(shí)候例如:Object object=new Object();那object就是一個(gè)強(qiáng)引用了。如果一個(gè)對(duì)象具有強(qiáng)引用,那就類似于必不可少的生活用品,垃圾回收器絕不會(huì)回收它。當(dāng)內(nèi)存空 間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足問(wèn)題。

3、軟引用(SoftReference)
   如果一個(gè)對(duì)象只具有軟引用,那就類似于可有可物的生活用品。如果內(nèi)存空間足夠,垃圾回收器就不會(huì)回收它,如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存。只 要垃圾回收器沒(méi)有回收它,該對(duì)象就可以被程序使用。軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存。 軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián) 合使用,如果軟引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。


4、弱引用(WeakReference)

   如果一個(gè)對(duì)象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。不過(guò),由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程, 因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。  弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回 收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。 

 5、虛引用(PhantomReference)

   '虛引用'顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在 任何時(shí)候都可能被垃圾回收。 虛引用主要用來(lái)跟蹤對(duì)象被垃圾回收的活動(dòng)。虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中。程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。程序如果發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì) 列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)。 

6、相關(guān)應(yīng)用

  在java.lang.ref包中提供了三個(gè)類:SoftReference類、WeakReference類和PhantomReference類,它 們分別代表軟引用、弱引用和虛引用。ReferenceQueue類表示引用隊(duì)列,它可以和這三種引用類聯(lián)合使用,以便跟蹤Java虛擬機(jī)回收所引用的對(duì) 象的活動(dòng)。

以下程序創(chuàng)建了一個(gè)String對(duì)象、ReferenceQueue對(duì)象和WeakReference對(duì)象:

以上程序代碼執(zhí)行完畢,內(nèi)存中引用與對(duì)象的關(guān)系如圖2所示



       圖2 'hello'對(duì)象同時(shí)具有強(qiáng)引用和弱引用

     在圖2中,帶實(shí)線的箭頭表示強(qiáng)引用,帶虛線的箭頭表示弱引用。從圖中可以看出,此時(shí)'hello'對(duì)象被str強(qiáng)引用,并且被一個(gè)WeakReference對(duì)象弱引用,因此'hello'對(duì)象不會(huì)被垃圾回收。

   在以下程序代碼中,把引用'hello'對(duì)象的str變量置為null,然后再通過(guò)WeakReference弱引用的get()方法獲得'hello'對(duì)象的引用:

    執(zhí)行完以上第④行后,內(nèi)存中引用與對(duì)象的關(guān)系如圖3所示,此 時(shí)'hello'對(duì)象僅僅具有弱引用,因此它有可能被垃圾回收。假如它還沒(méi)有被垃圾回收,那么接下來(lái)在第⑤行執(zhí)行wf.get()方法會(huì)返回 'hello'對(duì)象的引用,并且使得這個(gè)對(duì)象被str1強(qiáng)引用。再接下來(lái)在第⑥行執(zhí)行rq.poll()方法會(huì)返回null,因?yàn)榇藭r(shí)引用隊(duì)列中沒(méi)有任何 引用。ReferenceQueue的poll()方法用于返回隊(duì)列中的引用,如果沒(méi)有則返回null。



     圖3 'hello'對(duì)象只具有弱引用

    在以下程序代碼中,執(zhí)行完第④行后,'hello'對(duì)象僅僅具有弱引用。接下來(lái)兩次調(diào)用System.gc()方法,催促垃圾回收器工作,從而提高 'hello'對(duì)象被回收的可能性。假如'hello'對(duì)象被回收,那么WeakReference對(duì)象的引用被加入到ReferenceQueue中, 接下來(lái)wf.get()方法返回null,并且rq.poll()方法返回WeakReference對(duì)象的引用。圖4顯示了執(zhí)行完第⑧行后內(nèi)存中引用與 對(duì)象的關(guān)系。



  圖4 'hello'對(duì)象被垃圾回收,弱引用被加入到引用隊(duì)列

    在以下代碼References類中,依次創(chuàng)建了10個(gè)軟引用、10個(gè)弱引用和10個(gè)虛引用,它們各自引用一個(gè)Grocery對(duì)象。從程序運(yùn) 行時(shí)的打印結(jié)果可以看出,虛引用形同虛設(shè),它所引用的對(duì)象隨時(shí)可能被垃圾回收,具有弱引用的對(duì)象擁有稍微長(zhǎng)的生命周期,當(dāng)垃圾回收器執(zhí)行回收操作時(shí),有可 能被垃圾回收,具有軟引用的對(duì)象擁有較長(zhǎng)的生命周期,但在Java虛擬機(jī)認(rèn)為內(nèi)存不足的情況下,也會(huì)被垃圾回收。

     在Java集合中有一種特殊的Map類型:WeakHashMap, 在這種Map中存放了鍵對(duì)象的弱引用,當(dāng)一個(gè)鍵對(duì)象被垃圾回收,那么相應(yīng)的值對(duì)象的引用會(huì)從Map中刪除。WeakHashMap能夠節(jié)約存儲(chǔ)空間,可用來(lái)緩存那些非必須存在的數(shù)據(jù)。
     以下代碼MapCache類的main()方法創(chuàng)建了一個(gè)WeakHashMap對(duì)象,它存放了一組Key對(duì)象的弱引用,此外main()方法還創(chuàng)建了一個(gè)數(shù)組對(duì)象,它存放了部分Key對(duì)象的強(qiáng)引用。

程序輸出結(jié)果:

    從打印結(jié)果可以看出,當(dāng)執(zhí)行System.gc()方法后,垃圾回收器只會(huì)回收那些僅僅持有弱引用的Key對(duì)象。id可以被3整數(shù)的Key對(duì)象持有強(qiáng)引用,因此不會(huì)被回收。

7、使用軟引用構(gòu)建敏感數(shù)據(jù)的緩存

    7.1 為什么需要使用軟引用
    首先,我們看一個(gè)雇員信息查詢系統(tǒng)的實(shí)例。我們將使用一個(gè)Java語(yǔ)言實(shí)現(xiàn)的雇員信息查詢系統(tǒng)查詢存儲(chǔ)在磁盤文件或者數(shù)據(jù)庫(kù)中的雇員人事檔案信息。作為一 個(gè)用戶,我們完全有可能需要回頭去查看幾分鐘甚至幾秒鐘前查看過(guò)的雇員檔案信息(同樣,我們?cè)跒g覽WEB頁(yè)面的時(shí)候也經(jīng)常會(huì)使用“后退”按鈕)。這時(shí)我們 通常會(huì)有兩種程序?qū)崿F(xiàn)方式:一種是把過(guò)去查看過(guò)的雇員信息保存在內(nèi)存中,每一個(gè)存儲(chǔ)了雇員檔案信息的Java對(duì)象的生命周期貫穿整個(gè)應(yīng)用程序始終;另一種 是當(dāng)用戶開(kāi)始查看其他雇員的檔案信息的時(shí)候,把存儲(chǔ)了當(dāng)前所查看的雇員檔案信息的Java對(duì)象結(jié)束引用,使得垃圾收集線程可以回收其所占用的內(nèi)存空間,當(dāng) 用戶再次需要瀏覽該雇員的檔案信息的時(shí)候,重新構(gòu)建該雇員的信息。很顯然,第一種實(shí)現(xiàn)方法將造成大量的內(nèi)存浪費(fèi),而第二種實(shí)現(xiàn)的缺陷在于即使垃圾收集線程 還沒(méi)有進(jìn)行垃圾收集,包含雇員檔案信息的對(duì)象仍然完好地保存在內(nèi)存中,應(yīng)用程序也要重新構(gòu)建一個(gè)對(duì)象。我們知道,訪問(wèn)磁盤文件、訪問(wèn)網(wǎng)絡(luò)資源、查詢數(shù)據(jù)庫(kù) 等操作都是影響應(yīng)用程序執(zhí)行性能的重要因素,如果能重新獲取那些尚未被回收的Java對(duì)象的引用,必將減少不必要的訪問(wèn),大大提高程序的運(yùn)行速度。


    7.2 如果使用軟引用
    SoftReference的特點(diǎn)是它的一個(gè)實(shí)例保存對(duì)一個(gè)Java對(duì)象的軟引用,該軟引用的存在不妨礙垃圾收集線程對(duì)該Java對(duì)象的回收。也就是說(shuō), 一旦SoftReference保存了對(duì)一個(gè)Java對(duì)象的軟引用后,在垃圾線程對(duì)這個(gè)Java對(duì)象回收前,SoftReference類所提供的 get()方法返回Java對(duì)象的強(qiáng)引用。另外,一旦垃圾線程回收該Java對(duì)象之后,get()方法將返回null。

 看下面代碼:

     此時(shí),對(duì)于這個(gè)MyObject對(duì)象,有兩個(gè)引用路徑,一個(gè)是來(lái)自SoftReference對(duì)象的軟引用,一個(gè)來(lái)自變量aReference的強(qiáng)引用,所以這個(gè)MyObject對(duì)象是強(qiáng)可及對(duì)象。
     隨即,我們可以結(jié)束aReference對(duì)這個(gè)MyObject實(shí)例的強(qiáng)引用:
     aRef = null; 
     此后,這個(gè)MyObject對(duì)象成為了軟可及對(duì)象。如果垃圾收集線程進(jìn)行內(nèi)存垃圾收集,并不會(huì)因?yàn)橛幸粋€(gè)SoftReference對(duì)該對(duì)象的引用而始終 保留該對(duì)象。Java虛擬機(jī)的垃圾收集線程對(duì)軟可及對(duì)象和其他一般Java對(duì)象進(jìn)行了區(qū)別對(duì)待:軟可及對(duì)象的清理是由垃圾收集線程根據(jù)其特定算法按照內(nèi)存 需求決定的。也就是說(shuō),垃圾收集線程會(huì)在虛擬機(jī)拋出OutOfMemoryError之前回收軟可及對(duì)象,而且虛擬機(jī)會(huì)盡可能優(yōu)先回收長(zhǎng)時(shí)間閑置不用的軟 可及對(duì)象,對(duì)那些剛剛構(gòu)建的或剛剛使用過(guò)的“新”軟可反對(duì)象會(huì)被虛擬機(jī)盡可能保留。在回收這些對(duì)象之前,我們可以通過(guò):
     MyObject anotherRef=(MyObject)aSoftRef.get(); 
     重新獲得對(duì)該實(shí)例的強(qiáng)引用。而回收之后,調(diào)用get()方法就只能得到null了。


     7.3 使用ReferenceQueue清除失去了軟引用對(duì)象的SoftReference
     作為一個(gè)Java對(duì)象,SoftReference對(duì)象除了具有保存軟引用的特殊性之外,也具有Java對(duì)象的一般性。所以,當(dāng)軟可及對(duì)象被回收之后, 雖然這個(gè)SoftReference對(duì)象的get()方法返回null,但這個(gè)SoftReference對(duì)象已經(jīng)不再具有存在的價(jià)值,需要一個(gè)適當(dāng)?shù)那?除機(jī)制,避免大量SoftReference對(duì)象帶來(lái)的內(nèi)存泄漏。在java.lang.ref包里還提供了ReferenceQueue。如果在創(chuàng)建 SoftReference對(duì)象的時(shí)候,使用了一個(gè)ReferenceQueue對(duì)象作為參數(shù)提供給SoftReference的構(gòu)造方法,如:

    那么當(dāng)這個(gè)SoftReference所軟引用的aMyOhject被垃圾收集器回收的同時(shí),ref所強(qiáng)引用的SoftReference對(duì)象被列入 ReferenceQueue。也就是說(shuō),ReferenceQueue中保存的對(duì)象是Reference對(duì)象,而且是已經(jīng)失去了它所軟引用的對(duì)象的 Reference對(duì)象。另外從ReferenceQueue這個(gè)名字也可以看出,它是一個(gè)隊(duì)列,當(dāng)我們調(diào)用它的poll()方法的時(shí)候,如果這個(gè)隊(duì)列中 不是空隊(duì)列,那么將返回隊(duì)列前面的那個(gè)Reference對(duì)象。
    在任何時(shí)候,我們都可以調(diào)用ReferenceQueue的poll()方法來(lái)檢查是否有它所關(guān)心的非強(qiáng)可及對(duì)象被回收。如果隊(duì)列為空,將返回一個(gè) null,否則該方法返回隊(duì)列中前面的一個(gè)Reference對(duì)象。利用這個(gè)方法,我們可以檢查哪個(gè)SoftReference所軟引用的對(duì)象已經(jīng)被回 收。于是我們可以把這些失去所軟引用的對(duì)象的SoftReference對(duì)象清除掉。常用的方式為:

     理解了ReferenceQueue的工作機(jī)制之后,我們就可以開(kāi)始構(gòu)造一個(gè)Java對(duì)象的高速緩存器了。


     7.4通過(guò)軟可及對(duì)象重獲方法實(shí)現(xiàn)Java對(duì)象的高速緩存
 利用Java2平臺(tái)垃圾收集機(jī)制的特性以及前述的垃圾對(duì)象重獲方法,我們通過(guò)一個(gè)雇員信息查詢系統(tǒng)的小例子來(lái)說(shuō)明如何構(gòu)建一種高速緩存器來(lái)避免重復(fù)構(gòu)建同一個(gè)對(duì)象帶來(lái)的性能損失。我們將一個(gè)雇員的檔案信息定義為一個(gè)Employee類:

    這個(gè)Employee類的構(gòu)造方法中我們可以預(yù)見(jiàn),如果每次需要查詢一個(gè)雇員的信息。哪怕是幾秒中之前剛剛查詢過(guò)的,都要重新構(gòu)建一個(gè)實(shí)例,這是需要消耗很多時(shí)間的。下面是一個(gè)對(duì)Employee對(duì)象進(jìn)行緩存的緩存器的定義:

java代碼:
  1. import java.lang.ref.ReferenceQueue;      
  2. import java.lang.ref.SoftReference;      
  3. import java.util.Hashtable;      
  4. publicclass EmployeeCache {      
  5. staticprivate EmployeeCache cache;// 一個(gè)Cache實(shí)例    
  6. private Hashtable employeeRefs;// 用于Cache內(nèi)容的存儲(chǔ)    
  7. private ReferenceQueue q;// 垃圾Reference的隊(duì)列    
  8. // 繼承SoftReference,使得每一個(gè)實(shí)例都具有可識(shí)別的標(biāo)識(shí)。    
  9. // 并且該標(biāo)識(shí)與其在HashMap內(nèi)的key相同。    
  10. privateclass EmployeeRef extends SoftReference {      
  11. private String _key = '';      
  12. public EmployeeRef(Employee em, ReferenceQueue q) {      
  13. super(em, q);      
  14.            _key = em.getID();      
  15.        }      
  16.     }      
  17. // 構(gòu)建一個(gè)緩存器實(shí)例    
  18. private EmployeeCache() {      
  19.        employeeRefs = new Hashtable();      
  20.        q = new ReferenceQueue();      
  21.     }      
  22. // 取得緩存器實(shí)例    
  23. publicstatic EmployeeCache getInstance() {      
  24. if (cache == null) {      
  25.            cache = new EmployeeCache();      
  26.        }      
  27. return cache;      
  28.     }      
  29. // 以軟引用的方式對(duì)一個(gè)Employee對(duì)象的實(shí)例進(jìn)行引用并保存該引用    
  30. privatevoid cacheEmployee(Employee em) {      
  31.        cleanCache();// 清除垃圾引用    
  32.        EmployeeRef ref = new EmployeeRef(em, q);      
  33.        employeeRefs.put(em.getID(), ref);      
  34.     }      
  35. // 依據(jù)所指定的ID號(hào),重新獲取相應(yīng)Employee對(duì)象的實(shí)例    
  36. public Employee getEmployee(String ID) {      
  37.        Employee em = null;      
  38. // 緩存中是否有該Employee實(shí)例的軟引用,如果有,從軟引用中取得。    
  39. if (employeeRefs.containsKey(ID)) {      
  40.            EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID);      
  41.            em = (Employee) ref.get();      
  42.        }      
  43. // 如果沒(méi)有軟引用,或者從軟引用中得到的實(shí)例是null,重新構(gòu)建一個(gè)實(shí)例,    
  44. // 并保存對(duì)這個(gè)新建實(shí)例的軟引用    
  45. if (em == null) {      
  46.            em = new Employee(ID);      
  47.            System.out.println('Retrieve From EmployeeInfoCenter. ID='   ID);      
  48. this.cacheEmployee(em);      
  49.        }      
  50. return em;      
  51.     }      
  52. // 清除那些所軟引用的Employee對(duì)象已經(jīng)被回收的EmployeeRef對(duì)象    
  53. privatevoid cleanCache() {      
  54.        EmployeeRef ref = null;      
  55. while ((ref = (EmployeeRef) q.poll()) != null) {      
  56.            employeeRefs.remove(ref._key);      
  57.        }      
  58.     }      
  59. // 清除Cache內(nèi)的全部?jī)?nèi)容    
  60. publicvoid clearCache() {      
  61.        cleanCache();      
  62.        employeeRefs.clear();      
  63.        System.gc();      
  64.        System.runFinalization();      
  65.     }      
  66. }      

 8.使用弱引用構(gòu)建非敏感數(shù)據(jù)的緩存
     8.1全局 Map 造成的內(nèi)存泄漏
     無(wú)意識(shí)對(duì)象保留最常見(jiàn)的原因是使用Map將元數(shù)據(jù)與臨時(shí)對(duì)象(transient object)相關(guān)聯(lián)。假定一個(gè)對(duì)象具有中等生命周期,比分配它的那個(gè)方法調(diào)用的生命周期長(zhǎng),但是比應(yīng)用程序的生命周期短,如客戶機(jī)的套接字連接。需要將 一些元數(shù)據(jù)與這個(gè)套接字關(guān)聯(lián),如生成連接的用戶的標(biāo)識(shí)。在創(chuàng)建Socket時(shí)是不知道這些信息的,并且不能將數(shù)據(jù)添加到Socket對(duì)象上,因?yàn)椴荒芸刂?Socket 類或者它的子類。這時(shí),典型的方法就是在一個(gè)全局 Map 中存儲(chǔ)這些信息,如下面的 SocketManager 類所示:使用一個(gè)全局 Map 將元數(shù)據(jù)關(guān)聯(lián)到一個(gè)對(duì)象。

    這種方法的問(wèn)題是元數(shù)據(jù)的生命周期需要與套接字的生命周期掛鉤,但是除非準(zhǔn)確地知道什么時(shí)候程序不再需要這個(gè)套接字,并記住從 Map 中刪除相應(yīng)的映射,否則,Socket 和 User 對(duì)象將會(huì)永遠(yuǎn)留在 Map 中,遠(yuǎn)遠(yuǎn)超過(guò)響應(yīng)了請(qǐng)求和關(guān)閉套接字的時(shí)間。這會(huì)阻止 Socket 和 User 對(duì)象被垃圾收集,即使應(yīng)用程序不會(huì)再使用它們。這些對(duì)象留下來(lái)不受控制,很容易造成程序在長(zhǎng)時(shí)間運(yùn)行后內(nèi)存爆滿。除了最簡(jiǎn)單的情況,在幾乎所有情況下找出 什么時(shí)候 Socket 不再被程序使用是一件很煩人和容易出錯(cuò)的任務(wù),需要人工對(duì)內(nèi)存進(jìn)行管理。


     8.2如何使用WeakHashMap
     在Java集合中有一種特殊的Map類型—WeakHashMap,在這種Map中存放了鍵對(duì)象的弱引用,當(dāng)一個(gè)鍵對(duì)象被垃圾回收器回收時(shí),那么相應(yīng)的值 對(duì)象的引用會(huì)從Map中刪除。WeakHashMap能夠節(jié)約存儲(chǔ)空間,可用來(lái)緩存那些非必須存在的數(shù)據(jù)。關(guān)于Map接口的一般用法。
    下面示例中MapCache類的main()方法創(chuàng)建了一個(gè)WeakHashMap對(duì)象,它存放了一組Key對(duì)象的弱引用,此外main()方法還創(chuàng)建了一個(gè)數(shù)組對(duì)象,它存放了部分Key對(duì)象的強(qiáng)引用。

java代碼:
  1. import java.util.WeakHashMap;      
  2. class Element {      
  3. private String ident;      
  4. public Element(String id) {      
  5.        ident = id;      
  6.     }      
  7. public String toString() {      
  8. return ident;      
  9.     }      
  10. publicint hashCode() {      
  11. return ident.hashCode();      
  12.     }      
  13. publicboolean equals(Object obj) {      
  14. return obj instanceof Element && ident.equals(((Element) obj).ident);      
  15.     }      
  16. protectedvoid finalize(){      
  17.        System.out.println('Finalizing ' getClass().getSimpleName() ' ' ident);      
  18.     }      
  19. }      
  20. class Key extends Element{      
  21. public Key(String id){      
  22. super(id);      
  23.     }      
  24. }      
  25. class Value extends Element{      
  26. public Value (String id){      
  27. super(id);      
  28.     }      
  29. }      
  30. publicclass CanonicalMapping {      
  31. publicstaticvoid main(String[] args){      
  32. int size=1000;      
  33.        Key[] keys=new Key[size];      
  34.        WeakHashMap map=new WeakHashMap();      
  35. for(int i=0;i< SPAN>    
  36.            Key k=new Key(Integer.toString(i));      
  37.            Value v=new Value(Integer.toString(i));      
  38. if(i%3==0)      
  39.               keys[i]=k;      
  40.            map.put(k, v);      
  41.        }      
  42.        System.gc();      
  43.     }      
  44. }      

     從打印結(jié)果可以看出,當(dāng)執(zhí)行System.gc()方法后,垃圾回收器只會(huì)回收那些僅僅持有弱引用的Key對(duì)象。id可以被3整除的Key對(duì)象持有強(qiáng)引用,因此不會(huì)被回收。


    8.3用 WeakHashMap 堵住泄漏
    在 SocketManager 中防止泄漏很容易,只要用 WeakHashMap 代替 HashMap 就行了。(這里假定SocketManager不需要線程安全)。當(dāng)映射的生命周期必須與鍵的生命周期聯(lián)系在一起時(shí),可以使用這種方法。用 WeakHashMap修復(fù) SocketManager。

     8.4配合使用引用隊(duì)列
     WeakHashMap 用弱引用承載映射鍵,這使得應(yīng)用程序不再使用鍵對(duì)象時(shí)它們可以被垃圾收集,get() 實(shí)現(xiàn)可以根據(jù) WeakReference.get() 是否返回 null 來(lái)區(qū)分死的映射和活的映射。但是這只是防止 Map 的內(nèi)存消耗在應(yīng)用程序的生命周期中不斷增加所需要做的工作的一半,還需要做一些工作以便在鍵對(duì)象被收集后從 Map 中刪除死項(xiàng)。否則,Map 會(huì)充滿對(duì)應(yīng)于死鍵的項(xiàng)。雖然這對(duì)于應(yīng)用程序是不可見(jiàn)的,但是它仍然會(huì)造成應(yīng)用程序耗盡內(nèi)存。 
 引用隊(duì)列是垃圾收集器向應(yīng)用程序返回關(guān)于對(duì)象生命周期的信息的主要方法。弱引用有個(gè)構(gòu)造函數(shù)取引用隊(duì)列作為參數(shù)。如果用關(guān)聯(lián)的引用隊(duì)列創(chuàng)建弱引用,在弱引用對(duì)象成為 GC 候選對(duì)象時(shí),這個(gè)引用對(duì)象就在引用清除后加入到引用隊(duì)列中(具體參考上文軟引用示例)。
     WeakHashMap 有一個(gè)名為 expungeStaleEntries() 的私有方法,大多數(shù) Map 操作中會(huì)調(diào)用它,它去掉引用隊(duì)列中所有失效的引用,并刪除關(guān)聯(lián)的映射。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多