當弱引用物件成為集合元素時
當我們在系統用到某些佔用記憶體較多的大物件,且該物件並不會被頻繁使用(例如快取場景)時,若考慮效能因素,或許我們可以選擇使用弱引用(WeakReference)物件。弱引用物件就像是物件之中的“無間行者”,行走於“活動”與“非活動”狀態之間。即使該物件存在引用,垃圾回收器仍然可以對其進行回收,這使得我們對該物件的呼叫始終存在一種不可預知性,除非我們通過Target屬性賦給物件,以建立強引用,否則我們始終處於這種憂慮之中。這讓我們常常感到左右為難,但在一些追求效能的場景下,使用弱引用未嘗不是明智的選擇。只要我們遵循一定的原則,例如在每次呼叫弱引用物件時,首先判斷其是否為null,就不會存在太大的問題(如果考慮併發,則需要lock,通常需要做兩次對null的判斷,就如在Singleton模式中對併發支援的實現一樣)。然而,當我們在一個集合物件中儲存弱引用物件時,問題就出現了意想不到的變化。
首先是對集合Count屬性的判斷。如果一個集合物件在某個時刻儲存了10個弱引用物件,當我們呼叫該集合的Count屬性時,返回的值應該是多少?很顯然,我們不能做預先的判斷。事實上,因為弱引用物件的存在,一個本身執行緒安全的呼叫卻出現了併發問題。因為在呼叫Count屬性期間,GC正有可能回收集合中的某些元素物件。
其次是對迭代器的支援。我們知道,在對IEnumerable進行Foreach遍歷時,不允許我們Add或Remove集合的元素,否則遍歷就會失敗。如果沒有弱引用物件,一切都是美好的。但在我們遍歷儲存了弱引用物件的集合時,GC就會像幽靈一般,不知什麼時候鑽出來搗亂,改變集合元素的個數。很顯然,這樣的集合對迭代器的支援是不安全的。
實質上,這兩個問題的本源是相同的,起因就是弱引用的特殊性。如何解決這個問題?一個簡單辦法是定義自己的弱引用集合,對集合物件進行一個簡單的Wrapper,同時隱藏Count屬性,以及其對IEnumerable的支援。例如,定義一個弱引用列表:
{
private List<WeakReference> m_list;
public void Add(T object)
{
//這裡使用短弱引用,一般不建議使用長弱引用;
m_list.Add(new WeakReference(object));
}
//其它成員
}
WeakReferenceList類並沒有提供GetEnumerator()方法的必要,原因如前所述。至於Count屬性,我們是否可以通過查詢條件,以過濾那些值為null的物件呢?例如:
{
get
{
return m_list.Count(e => e.IsAlive);
}
}
表面看來這是可行的,可是彼時返回的值,在使用該值的時候未必正確,即使對其進行lock,也無法保證其正確性。與其如此,還不如不提供Count屬性。
剩下一個問題是如何獲得WeakReferenceList的元素?我們需要為其實現特有的索引器。例如:
{
get
{
//這裡仍然使用了Count屬性(這說明我們可以定義一個私有屬性Count)
if (index < 0 || index >= this.Count)
{
throw new IndexOutOfRangeException();
}
else
{
if (m_list[index].Target != null)
{
return (T)m_list[index].Target;
}
else
{
throw new Exception(“The object is collected by GC.”)
}
}
}
}
private int Count
{
get
{
return m_list.Count(e => e.IsAlive);
}
}
更好地管理弱引用物件的集合是HashTable,這也是快取的一種好的儲存機制。關於HashTable對弱引用物件的應用,請參見Jared Parsons的文章Building a WeakReference Hashtable。實際上,本文正是借鑑了該文的思想。
本文轉自wayfarer51CTO部落格,原文連結:http://blog.51cto.com/wayfarer/280097,如需轉載請自行聯絡原作者
相關文章
- [譯] 對元素持有弱引用的 Swift 陣列Swift陣列
- Java的強引用、軟引用、弱引用、虛引用Java
- 【JVM】如何理解強引用、軟引用、弱引用、虛引用?JVM
- Java四種引用包括強引用,軟引用,弱引用,虛引用。Java
- 理解Java的強引用、軟引用、弱引用和虛引用Java
- Java中的弱引用Java
- Java弱引用與WeakHashMapJavaHashMap
- 時間物件、引用型別物件型別
- 強引用、軟引用、弱引用、幻象引用有什麼區別?
- Java/Android中的強引用、軟引用、弱引用、虛引用JavaAndroid
- java的強引用、軟引用、弱引用、幻象引用,引用佇列總結Java佇列
- Java四大引用詳解:強引用、軟引用、弱引用、虛引用Java
- Java中的四種引用方式(強引用、軟引用、弱引用、虛引用)Java
- 強引用、軟引用、弱引用、幻象引用再不理解就晚了
- Swift 4 弱引用實現Swift
- Python 弱引用 學習Python
- 理解Java中的弱引用Java
- Java引用型別解析:掌握強引用、軟引用、弱引用和幻象引用的妙用Java型別
- 有效避免OOM--合理使用軟引用和弱引用OOM
- 從原始碼解析 Swift 弱引用原始碼Swift
- weak 弱引用的實現方式
- Java中的弱引用詳解Java
- javascript獲取當前li元素在集合中的位置JavaScript
- 面試官問:ThreadLocal中的鍵為什麼是弱引用?面試thread
- 當API成為服務API
- Android效能優化篇:使用軟引用和弱引用Android優化
- 為什麼Date物件被設定成過時了物件
- 集合競價如何看強弱?
- #### 使用方法引用的使用場景--通過物件名引用成員方法物件
- JavaScript 元素集合JavaScript
- Java常見知識點彙總(⑲)——Java中的強引用、弱引用、軟引用、虛引用Java
- Android開發優化之——使用軟引用和弱引用Android優化
- Java集合不能存放基本資料型別,只存放物件的引用Java資料型別物件
- js將dom元素集合轉換為陣列JS陣列
- 在Java中對集合當中的物件進行排序Java物件排序
- PHP 物件導向 (四)類物件賦值為引用傳遞PHP物件賦值
- 值物件與引用物件物件
- python3學習筆記之 強引用和弱引用Python筆記