網站首頁 編程語言 正文
有的時候,我們需要給某些數據添加一些附加信息,一種常用的做法是使用一個Dictionary在填充這些附加信息如:
var data = new Data();
var tag = new Tag();
var dictionary = new Dictionary<Data, Tag>();
dictionary[data] = tag;
這么做本身沒有什么問題,但是卻又一個不小的隱患,那就是在dictionary中保存著了data和tag的引用。當data不再使用的時候,需要將其從dictionary中移除,否則data和tag得不到釋放。我們可以用如下代碼說明這個問題:(注意,由于Debug模式有時會影響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);
}
從運行結果中可以看出,只有創建的輸出,而沒有釋放的輸出。這個就屬于資源泄漏了。雖然可以通過手動在dictionary中刪除data來實現資源的釋放,但是這樣就要求我們手動管理對象的生命周期了,而這往往不是一個比較容易做到的事情。
究其原因,是由于dictionary中保持著強引用、導致GC不會對其進行回收。找到了這個原因后,那就有相應的對策了,那就是改用弱引用來建立關聯,這樣數據就會被GC釋放了。這種觀念關系我們通常稱為弱字典——WeakDictionary。弱字典也是保存著Key和Value的鍵值對,它滿足如下需求:
字典中保存著Key的弱引用,即使不釋放Key值,也可以被GC回收。
字典中保存的Value的強引用,Key沒有被GC回收前,Value不會被GC回收。
當Key被GC回收時,關聯關系從字典中移除,Value也能被GC回收。
知道了需求后,接下來就可以對Dictionary進行簡單的封裝,將其改造成弱字典了。
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);
}
運行這段代碼后,我們就會發現,Data數據能釋放了,但是并不完善,具體體現在如下方面:
Tag保存的仍然是強引用,得不到釋放
Key數據并不是Data類型了,存在一個檢索的問題,否則無法CRUD。
對于第一個問題,可以通過一個Timer來定時清理已經釋放了的Key來解決;對于第二個問題,則需要在內部通過key來建立Hash表來解決。具體的實現還有點麻煩,也會引入一些新的問題,這里就不繼續列舉了。
之所以不繼續改造下去了,是因為這里我是在造重復輪子,.Net的BCL中本身就已經提供了一個弱字典——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);
}
從運行結果來看,GC結束后,Key和Value都被GC回收掉了(再次強調,需要運行在Release版本下)。
這個類放置在System.Runtime.CompilerServices下,也很少見到有書里面介紹到它。這里我就簡單的介紹一下其接口吧:
dictionary.Add(data, tag); //添加
dictionary.TryGetValue(data, out tag); //查詢
dictionary.Remove(data); //刪除
這三個是它比較常見的接口,另外還有兩個不大用的接口,這里就不多介紹了。
最后,簡單的試了它的性能,基本上和Dictionary差不多,查詢效率還是非常高的,內部應該也是一個Hash表。
原文鏈接:https://www.cnblogs.com/TianFang/p/3546556.html
相關推薦
- 2022-07-31 Android中View.post和Handler.post的關系_Android
- 2022-08-02 C#中DateTime函數的詳細用法_C#教程
- 2022-12-12 C語言實現循環打印星號圖形再鏤空_C 語言
- 2022-10-19 R語言安裝以及手動安裝devtools的詳細圖文教程_R語言
- 2022-08-15 棧(Stack)和隊列(Queue)的基本操作
- 2022-09-04 關于python?DataFrame的合并方法總結_python
- 2022-07-24 C++深入刨析類與對象的使用_C 語言
- 2022-03-14 Spring Redis Cache @Cacheable 大并發下返回null
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支