在python的標準類庫中發現有weakref這個模組,比較有趣。依稀想起在java中似乎也有個叫做WeakReference的類,只是當時沒有太留心,此時好奇心起,在網上找到這篇文章,講的挺好,摘要一下。
在Java 1.2中就引入了java.lang.ref這個包,WeakReference就屬於這個包。WeakReference是幹嘛的呢,一言弊之,它是和Java中的記憶體回收相關的。如果一個對象只有WeakReference引用它,那麼這個對象就可能被記憶體回收行程回收。
在什麼場合下應用WeakReference呢?
有時我們會碰到一些不能繼承的類,如final class, 或者通過Factory建立的對象,它對外只暴露一個介面,我們無法知道它的具體實作類別,自然也無法繼承它。假如我們要使用一個Widget類,因為某種 緣故,我們無法繼承該類來加入某個功能。但是,我們必須將每個Widget對象和某個序號關聯,而Widget本身沒有serial number這個屬性,這時該怎麼做呢?
你也許已經想到,用HashMap!對,像這樣:
1.serialNumberMap.put(widget, widgetSerialNumber);
這看起來工作的很好。但是,有個問題:當我們不再需要某個Widget的serial number資訊,此時應該從HashMap中將這個Entry移除,如果我們忘記了怎麼辦?因為HashMap中持有對這個對象的引用,這個對象永遠不 會被記憶體回收行程回收,這就造成了記憶體流失!這意味著我們需要像沒有記憶體回收功能的語言一樣,手動管理記憶體!但是我們用的是Java.....
另一個很常見的問題是緩衝。如果使用強引用,那麼我們緩衝的對象就會一直滯留在記憶體中,不會被回收,除非我們手動的將其從緩衝中移除。此外,這還需要我們決定何時從緩衝中移除對象,又一個手動管理記憶體的問題!
此時,WeakReference就顯示出它的價值了。如何建立一個WeakReference呢?很簡單:
1.WeakReference<widget> weakWidget = newWeakReference<widget>(widget);2.Widget w = weakWidget.get();
要注意的是,當調用weakReference.get()可能返回null(意味著指向的對象已經被回收)。其實,對於Widget serial number這個問題,最簡單的方法是使用WeakHashMap,它的使用和普通的HashMap完全一樣,不同點在於,WeakHashMap的key被實現為一種WeakReference(注意,是key而不是value),當key對象被回收後,WeakHashMap會自動將對應的entry移除。更精確的說,對於一個給定的鍵,其映射的存在並不阻止記憶體回收行程對該鍵的回收。
Java中有四種類型的引用,按照強弱關係依次為:Strong Reference>Soft Reference>WeakReference> Phantom Reference。
其中,我們平常用的就是Strong Reference,而Phantom Reference很少用到,因此這裡不去研究了,那麼什麼是Soft Reference呢?
Soft Reference和weak reference的區別是:一旦gc發現對象是weak reference可達就會把它放到ReferenceQueue中,然後等下次gc時回收它;當對象是Soft reference可達時,gc可能會向作業系統申請更多記憶體,而不是直接回收它,當實在沒轍了才回收它。像cache系統,最適合用Soft reference。讓gc來替我們決定什麼時候回收對象以及回收哪些對象。