作者: Tomex Ou
版本歷史:
2008/09/28 AM 02:06:35 研究ASP.NET快取機制時,不小心引發的解題好奇心。
Weak Reference
弱式參考(Weak Reference)MSDN原文定義:
http://msdn.microsoft.com/en-us/library/ms404247.aspx
多數人看了上述文章,有看沒有懂,經過我一番查文推敲,用一些例子來形容解釋
讓大家多少有一點概念。
在.NET程式語法裏:
MyClass s1 = new MyClass("123"); // s1指向"123"的記憶體存放位置
MyClass s2 = s1; // s2指向"123"的記憶體存放位置
這時候記憶體"123"位置的reference count = 2 (以下簡稱RC)
RC會在s1或s2失去可視範圍(var scope)或為null時而減少
當RC= 0時,記憶體"123"就會被Garge Collector (GC)收集標記
當RC > 0時,該指向的記憶體並不會被GC標記
這s1, s2為活用狀態(active)的變數,都稱為該記憶體"123"的Strong References.
當Strong References不存在時(RC=0),且尚未被GC收集之前的這段期間內
假如可以有個機制跟這些待回收的記憶體空間作連結(前提是不影響GC流程,且保持RC=0)
那麼若需要再重新與這些廢棄記憶體配置作Strong Reference保留
就等於多了一個吃回頭草的機會。
這個機制就稱為「Weak Reference」,它不會造成RC增加,依然可以被GC標記收集。
所以Weak Reference類別會被創造的原因,就如同我們把家裏的垃圾丟到垃圾場,
在垃圾車真正把它運走之前,我們都有機會重新建立Strong Reference,而將它們保留下來。
一旦垃圾車(GC)來了,只會運走那些沒再被Strong Reference的垃圾。
ASP.NET有一個類別叫Cache(快取),當你使用Cache.Insert(object)時,它會把該object物件轉成byte[]複製至它的所佔記憶體內暫存
等一段時間失效後,就自動移除配置的記憶體項目,清除與項目之間的Strong References,而建立彼此的Weak Reference.
一旦需要重新再加入object值時,就可以透過其Weak Reference重新找到該位址
而建立彼此的Strong Reference,形成空間保留,也加速了建立的效率。
Weak Reference特別對記憶體配置大的class類別有助益,實作方式可參考以下網址之sample code部分:
http://msdn.microsoft.com/en-us/library/system.weakreference.aspx
_cache = new Dictionary();
但讀者會問,你講的是一種不錯的設計概念,但跟我有啥關係?
就好像買電視,買方在乎的是電視外觀及影像品質,賣方若一直介紹電視機內部核心設計機制,豈不是浪費彼此時間?
沒錯,我也是正常人,也不是吃飽沒事幹去讀Weak Reference概念
而是在實作ASP.NET Cache中,發現一篇文章指出乍似直覺的程式語法,可能會犯下的Null錯誤:
http://blog.miniasp.com/post/2008/01/Correct-using-Cache-in-ASPNET.aspx
該篇文章指出正確的判定Cache方式寫法應該如下:
MyClass class1 = Cache["Key"] as MyClass ;
if (class1 != null)
{
string name = class1.Name;
}
為什麼?? 文章中只指出一個方向,也就是我去研究Weak Reference的主要動機。
在Cache項目過期失效或被強制移除,雖然該塊Data記憶體區塊之Strong Reference被移除(Cache["Key"]=null)
但實際上它仍是以Weak Reference方式跟項目作連繫,直到它真正被GC收集之前。
變數class1先向該記憶體區塊請求建立一個Strong Reference,它會透過類別中的Weak Reference去檢查是否被GC收集否?
假如被GC了,就傳回null,否則就成功建立Strong Reference,該記憶體區塊Reference Count + 1,避免被GC收集。
反觀文章中的錯誤範例,因為沒有事先確定是否可對這些記憶體配置成功建立一個Strong Reference,
所以有可能會發生NullReferenceException。
if (Cache["Key"] != null)
{
string name = ((MyClass)Cache["Key"]).Name;
}
希望透過這些解釋說明,能對Weak Reference有些概念,比起看那些隱晦的原文定義,幸福多了。