.Net中的弱引用字典WeakDictionary和ConditionalWeakTable介紹
有的時(shí)候,我們需要給某些數(shù)據(jù)添加一些附加信息,一種常用的做法是使用一個(gè)Dictionary在填充這些附加信息如:
var data = new Data(); var tag = new Tag(); var dictionary = new Dictionary<Data, Tag>(); dictionary[data] = tag;
這么做本身沒有什么問題,但是卻又一個(gè)不小的隱患,那就是在dictionary中保存著了data和tag的引用。當(dāng)data不再使用的時(shí)候,需要將其從dictionary中移除,否則data和tag得不到釋放。我們可以用如下代碼說明這個(gè)問題:(注意,由于Debug模式有時(shí)會(huì)影響GC,本文代碼需行在Release模式下)
class Tag { public Tag() { Console.WriteLine("Create Tag"); } ~Tag() { Console.WriteLine("Release Tag"); } } class Data { public Data() { Console.WriteLine("Create Data"); } ~Data() { Console.WriteLine("Release Data"); } } static void Main(string[] args) { var data = new Data(); var tag = new Tag(); var dictionary = new Dictionary<Data, Tag>(); dictionary[data] = tag; data = null; GC.Collect(); Console.WriteLine("After GC"); Console.ReadLine(); Console.WriteLine(dictionary); }
從運(yùn)行結(jié)果中可以看出,只有創(chuàng)建的輸出,而沒有釋放的輸出。這個(gè)就屬于資源泄漏了。雖然可以通過手動(dòng)在dictionary中刪除data來實(shí)現(xiàn)資源的釋放,但是這樣就要求我們手動(dòng)管理對(duì)象的生命周期了,而這往往不是一個(gè)比較容易做到的事情。
究其原因,是由于dictionary中保持著強(qiáng)引用、導(dǎo)致GC不會(huì)對(duì)其進(jìn)行回收。找到了這個(gè)原因后,那就有相應(yīng)的對(duì)策了,那就是改用弱引用來建立關(guān)聯(lián),這樣數(shù)據(jù)就會(huì)被GC釋放了。這種觀念關(guān)系我們通常稱為弱字典——WeakDictionary。弱字典也是保存著Key和Value的鍵值對(duì),它滿足如下需求:
字典中保存著Key的弱引用,即使不釋放Key值,也可以被GC回收。
字典中保存的Value的強(qiáng)引用,Key沒有被GC回收前,Value不會(huì)被GC回收。
當(dāng)Key被GC回收時(shí),關(guān)聯(lián)關(guān)系從字典中移除,Value也能被GC回收。
知道了需求后,接下來就可以對(duì)Dictionary進(jìn)行簡單的封裝,將其改造成弱字典了。
static void Main(string[] args) { var data = new Data(); var tag = new Tag(); var dictionary = new Dictionary<WeakReference<Data>, Tag>(); var key = new WeakReference<Data>(data); dictionary[key] = tag; data = null; GC.Collect(); Console.WriteLine("After GC"); Console.ReadLine(); Console.WriteLine(dictionary); }
運(yùn)行這段代碼后,我們就會(huì)發(fā)現(xiàn),Data數(shù)據(jù)能釋放了,但是并不完善,具體體現(xiàn)在如下方面:
Tag保存的仍然是強(qiáng)引用,得不到釋放
Key數(shù)據(jù)并不是Data類型了,存在一個(gè)檢索的問題,否則無法CRUD。
對(duì)于第一個(gè)問題,可以通過一個(gè)Timer來定時(shí)清理已經(jīng)釋放了的Key來解決;對(duì)于第二個(gè)問題,則需要在內(nèi)部通過key來建立Hash表來解決。具體的實(shí)現(xiàn)還有點(diǎn)麻煩,也會(huì)引入一些新的問題,這里就不繼續(xù)列舉了。
之所以不繼續(xù)改造下去了,是因?yàn)檫@里我是在造重復(fù)輪子,.Net的BCL中本身就已經(jīng)提供了一個(gè)弱字典——ConditionalWeakTable,通過ConditionalWeakTable改造上述代碼如下:
static void Main(string[] args) { var data = new Data(); var tag = new Tag(); var dictionary = new ConditionalWeakTable<Data, Tag>(); dictionary.Add(data, tag); data = null; GC.Collect(); Console.WriteLine("After GC"); Console.ReadLine(); Console.WriteLine(dictionary); }
從運(yùn)行結(jié)果來看,GC結(jié)束后,Key和Value都被GC回收掉了(再次強(qiáng)調(diào),需要運(yùn)行在Release版本下)。
這個(gè)類放置在System.Runtime.CompilerServices下,也很少見到有書里面介紹到它。這里我就簡單的介紹一下其接口吧:
dictionary.Add(data, tag); //添加 dictionary.TryGetValue(data, out tag); //查詢 dictionary.Remove(data); //刪除
這三個(gè)是它比較常見的接口,另外還有兩個(gè)不大用的接口,這里就不多介紹了。
最后,簡單的試了它的性能,基本上和Dictionary差不多,查詢效率還是非常高的,內(nèi)部應(yīng)該也是一個(gè)Hash表。
到此這篇關(guān)于.Net弱引用字典WeakDictionary和ConditionalWeakTable的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
asp.net關(guān)于Cookie跨域(域名)的問題
Cookie是一個(gè)偉大的發(fā)明,它允許Web開發(fā)者保留他們的用戶的登錄狀態(tài)。但是當(dāng)你的站點(diǎn)有一個(gè)以上的域名時(shí)就會(huì)出現(xiàn)問題了。在Cookie規(guī)范上說,一個(gè)cookie只能用于一個(gè)域名,不能夠發(fā)給其它的域名。因此,如果在瀏覽器中對(duì)一個(gè)域名設(shè)置了一個(gè)cookie,這個(gè)cookie對(duì)于其它的域名將無效。如果你想讓你的用戶從你的站點(diǎn)中的其中一個(gè)進(jìn)行登錄,同時(shí)也可以在其它域名上進(jìn)行登錄,這可真是一個(gè)大難題。2012-12-12Asp.net 獲取指定目錄下的后綴名為".doc" 的所有文件名和文件路徑
Asp.net 獲取指定目錄下的后綴名為“.doc” 的所有文件名和文件路徑,幫寫一個(gè)方法2011-07-07ASP.NET數(shù)據(jù)庫緩存依賴實(shí)例分析
這篇文章主要介紹了ASP.NET數(shù)據(jù)庫緩存依賴,以實(shí)例的形式分析總結(jié)了數(shù)據(jù)庫緩存依賴的原理與用法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10將FreeTextBox做成控件添加到工具箱中的具體操作方法
以下是對(duì)將FreeTextBox做成控件添加到工具箱中的具體操作方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下2013-09-09asp.net 網(wǎng)頁動(dòng)態(tài)查詢條件的實(shí)現(xiàn)
最近有一個(gè)需求,會(huì)在 mongodb 中插入各種類型的數(shù)據(jù),算是記錄業(yè)務(wù)日志的數(shù)據(jù)庫吧。因?yàn)闃I(yè)務(wù)對(duì)象類型都不同,所以插入的數(shù)據(jù)格式也完全不同2012-10-10ASP.NET全棧開發(fā)教程之前后臺(tái)校驗(yàn)結(jié)合詳解
這篇文章主要給大家介紹了關(guān)于ASP.NET全棧開發(fā)教程之前后臺(tái)校驗(yàn)結(jié)合的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07