.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;這么做本身沒(méi)有什么問(wèn)題,但是卻又一個(gè)不小的隱患,那就是在dictionary中保存著了data和tag的引用。當(dāng)data不再使用的時(shí)候,需要將其從dictionary中移除,否則data和tag得不到釋放。我們可以用如下代碼說(shuō)明這個(gè)問(wèn)題:(注意,由于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)建的輸出,而沒(méi)有釋放的輸出。這個(gè)就屬于資源泄漏了。雖然可以通過(guò)手動(dòng)在dictionary中刪除data來(lái)實(shí)現(xiàn)資源的釋放,但是這樣就要求我們手動(dòng)管理對(duì)象的生命周期了,而這往往不是一個(gè)比較容易做到的事情。
究其原因,是由于dictionary中保持著強(qiáng)引用、導(dǎo)致GC不會(huì)對(duì)其進(jìn)行回收。找到了這個(gè)原因后,那就有相應(yīng)的對(duì)策了,那就是改用弱引用來(lái)建立關(guān)聯(lián),這樣數(shù)據(jù)就會(huì)被GC釋放了。這種觀(guān)念關(guān)系我們通常稱(chēng)為弱字典——WeakDictionary。弱字典也是保存著Key和Value的鍵值對(duì),它滿(mǎn)足如下需求:
字典中保存著Key的弱引用,即使不釋放Key值,也可以被GC回收。
字典中保存的Value的強(qiáng)引用,Key沒(méi)有被GC回收前,Value不會(huì)被GC回收。
當(dāng)Key被GC回收時(shí),關(guān)聯(lián)關(guān)系從字典中移除,Value也能被GC回收。
知道了需求后,接下來(lái)就可以對(duì)Dictionary進(jìn)行簡(jiǎ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類(lèi)型了,存在一個(gè)檢索的問(wèn)題,否則無(wú)法CRUD。
對(duì)于第一個(gè)問(wèn)題,可以通過(guò)一個(gè)Timer來(lái)定時(shí)清理已經(jīng)釋放了的Key來(lái)解決;對(duì)于第二個(gè)問(wèn)題,則需要在內(nèi)部通過(guò)key來(lái)建立Hash表來(lái)解決。具體的實(shí)現(xiàn)還有點(diǎn)麻煩,也會(huì)引入一些新的問(wèn)題,這里就不繼續(xù)列舉了。
之所以不繼續(xù)改造下去了,是因?yàn)檫@里我是在造重復(fù)輪子,.Net的BCL中本身就已經(jīng)提供了一個(gè)弱字典——ConditionalWeakTable,通過(guò)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é)果來(lái)看,GC結(jié)束后,Key和Value都被GC回收掉了(再次強(qiáng)調(diào),需要運(yùn)行在Release版本下)。
這個(gè)類(lèi)放置在System.Runtime.CompilerServices下,也很少見(jiàn)到有書(shū)里面介紹到它。這里我就簡(jiǎn)單的介紹一下其接口吧:
dictionary.Add(data, tag); //添加
dictionary.TryGetValue(data, out tag); //查詢(xún)
dictionary.Remove(data); //刪除這三個(gè)是它比較常見(jiàn)的接口,另外還有兩個(gè)不大用的接口,這里就不多介紹了。
最后,簡(jiǎn)單的試了它的性能,基本上和Dictionary差不多,查詢(xún)效率還是非常高的,內(nèi)部應(yīng)該也是一個(gè)Hash表。
到此這篇關(guān)于.Net弱引用字典WeakDictionary和ConditionalWeakTable的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Json數(shù)據(jù)轉(zhuǎn)換list對(duì)象實(shí)現(xiàn)思路及代碼
本文為大家詳細(xì)介紹下Json數(shù)據(jù)轉(zhuǎn)換list對(duì)象的具體實(shí)現(xiàn),感興趣的朋友可以參考下哈,希望對(duì)你有所幫助2013-04-04
GridView自定義分頁(yè)實(shí)例詳解(附demo源碼下載)
這篇文章主要介紹了GridView自定義分頁(yè)的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了GridView自定義分頁(yè)所涉及的樣式布局及功能實(shí)現(xiàn)相關(guān)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-03-03
asp.net 驗(yàn)證碼的簡(jiǎn)單制作(vb.net+C#)
asp.net中實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼的方法,需要的朋友可以參考下2012-05-05
詳細(xì)說(shuō)明asp.net中datareader 和 dataset 的區(qū)別
asp.net中datareader 和 dataset的區(qū)別主要是在獲取數(shù)據(jù)的機(jī)制和獲取數(shù)據(jù)的方式方面,下面我們來(lái)看教程2013-08-08
.NET 8 高性能跨平臺(tái)圖像處理庫(kù) ImageSharp 詳解
ImageSharp是.NET8的高性能跨平臺(tái)圖像處理庫(kù),適用于多種開(kāi)發(fā)場(chǎng)景,它支持廣泛的圖像格式和圖像處理操作,如調(diào)整大小、裁剪、旋轉(zhuǎn)、濾鏡效果等,ImageSharp通過(guò)NuGet安裝簡(jiǎn)便,易于在項(xiàng)目中集成使用,本文詳細(xì)介紹了ImageSharp的功能及使用方法,是開(kāi)發(fā)者進(jìn)行圖像處理的優(yōu)選工具2024-11-11
.Net Core讀取Json配置文件的實(shí)現(xiàn)示例
這篇文章主要介紹了.Net Core讀取Json配置文件的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
.net core版 文件上傳/ 支持批量上傳拖拽及預(yù)覽功能(bootstrap fileinput上傳文件)
本篇內(nèi)容主要解決.net core中文件上傳的問(wèn)題 開(kāi)發(fā)環(huán)境:ubuntu+vscode.本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2017-03-03
Visual Studio 2010崩潰重啟問(wèn)題(源文件編譯崩潰)
在使用Visual Studio 2010突然出現(xiàn)崩潰現(xiàn)象:源文件修改只要一編譯,馬上就崩潰.搜索了很多的方法也不見(jiàn)效果,經(jīng)過(guò)近1天的折騰,已經(jīng)決定重裝Windows 7了,遇到此問(wèn)題的朋友們可以看看哦,或許對(duì)你有所幫助2013-01-01

