2014年7月25日 星期五

Weak References

Strong references
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


沒有留言:

張貼留言