Strong reference是最常見的Java reference,舉例來說:
StringBuffer buffer = new StringBuffer();
- 產生一個StringBuffer物件,並將一個strong reference存到buffer變數中。
- strong指的是它和garbage collector的關係。
- 如果一個物件是reachable via a chain of strong references,它就不適合被garbage collect。
When strong references are too strong
當我們使用image cache時,若搭配strong reference,那麼這些image會一直保存在memory裡面。你必須自己決定何時不需要某個image並將它從cache中移除,但這樣的工作適合由garbage collection來處理的。
Weak references
weak reference簡單地說就是一個不夠強的reference,無法強迫一個物件一直存留在memory中。它可以幫助garbage collector決定物件的reachability,所以你就不用自己做。以下為一個例子:
WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
- 可以使用weakWidget.get( )來取得實際的Widget物件。
- 當這個widget物件沒有strong reference指向它時,可能會被garbage collection,此時weakWidget.get( )會return null。
- 當你想追蹤Widget物件的序號,但Widget class中並沒有這個項目,而且也不允許extend它,此時可以用HashMap來處理:
serialNumberMap.put(widget, widgetSerialNumber);- 但如果當序號沒用的時候沒去移除entry,在沒有garbage collector的語言中會有memory leak。
- 相同的我們也必須自己去管理這個HashMap何時該移除entry。
- 可以改用WeakHashMap,它跟HashMap差在會把key (不是value)作為weak reference。
- 當它的key變成garbage,則其value會自動被移除。
Reference queues
- 一旦WeakReference開始return null,代表它所指到的物件已經變成garbage,也代表這個WeakReference不再被需要,所以此時可以做清理的動作。
- 以WeakHashMap為例,要把已經沒用的entries移除。
- ReferenceQueue class可便於追蹤這些dead references。
- 若你把一個ReferenceQueue放到WeakReference的constructor,當reference所指的物件變成garbage了,則這個reference物件會自動插入reference queue中。你就可以每隔一段時間對這個ReferenceQueue做清理的動作。
Soft references
- 一個物件只有在weakly reachable(最強的reference是WeakReference)才會在下一次的garbage collection cycle被丟棄。但softly reachable的物件還是會保留一段時間。
- 實際上softly reachable的物件,只要memory足夠就會一直保留著。
- 這對於製作cache是最好用的(例如image cache)。
Phantom references
- 其get( ) method永遠return null
- 它的用途只有在追蹤什麼時候被放入ReferenceQueue,也就是知道何時所指的object死了。
- 它和WeakReference的差別在於enqueue的時機不同。
- WeakReference是當object變成weakly reachable時去做enqueue,這個時間點是在finalization或garbage collection實際發生之前。理論上物件是可以藉由非正統的finalize() method來復活,但WeakReference仍然是死的。
- PhantomReference只有在物件真正從memory中被移除時才會被enqueue。而get( ) method之所以永遠return null是為了避免你將物件復活。
- PhantomReference的兩大用途:
1. 得知物件何時真正從object中移除
- 例如等到它真的發生,再去load下一張圖,確保OutOfMemory不會發生
2. 避免在finalize( ) method中產生新的strong reference以復活物件的問題
- 問題在於Override finalize( )的物件要在至少兩個garbage collection cycle才會被當作garbage。
- finalization有可能不會及時執行,可能在等待finalization的過程中又經過了數個cycle,這代表實際上去清除garbage物件會有delay發生。這也是為什麼有時候,大部分的heap都是garbage但仍然發生OutOfMemory的原因。
強度:
Strong => Soft => Weak => Phantom