使用.Net中的WeakDictionary — ConditionalWeakTable
有的时候,我们需要给某些数据添加一些附加信息,一种常用的做法是使用一个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表,。
使用.Net中的WeakDictionary — ConditionalWeakTable的更多相关文章
- Python开源框架
info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...
- [转载] .NET 中可以有类似 JVM 的幻像引用吗?
近日发现一篇不错的文章,文中列举了一些 GC 场景,探讨了 在 .NET 中是需要实现像 JVM 的中的幻像引用.有人质疑其不切实际,也有像 Ayende 大神一言不合就自己做了个 demo. Do ...
- ASP.NET Core 中的 ObjectPool 对象重用(二)
前言 上一篇文章主要介绍了ObjectPool的理论知识,再来介绍一下Microsoft.Extensions.ObjectPool是如何实现的. 核心组件 ObjectPool ObjectPool ...
- mapreduce中一个map多个输入路径
package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...
- Hadoop 中利用 mapreduce 读写 mysql 数据
Hadoop 中利用 mapreduce 读写 mysql 数据 有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...
- Python中的多进程与多线程(一)
一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Angular杂谈系列1-如何在Angular2中使用jQuery及其插件
jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...
- 关于CryptoJS中md5加密以及aes加密的随笔
最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...
随机推荐
- MyBatis对象关联关系---- association与collection
Mybatis处理“一对多”的关系时,需要用到associasion元素.处理”多对一“用collection元素来实现(这两个元素在之前mapper文件中提到过). 本例子中,假设一名User可以有 ...
- bzoj4430 [Nwerc2015]Guessing Camels赌骆驼
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4430 [题解] 把每只骆驼在第一个人.第二个人.第三个人的位置找出来,然后做三维偏序即可. ...
- [Leetcode Week2]Sort List
Sort List题解 题目来源:https://leetcode.com/problems/sort-list/description/ Description Sort a linked list ...
- UVALIVE 2954 Task Sequences
竞赛图:图中的任意两点间有且仅有一条有向弧连接 求竞赛图中的哈密顿路的算法: 首先,由数学归纳法可证竞赛图在n>=2时必存在哈密顿路: (1)n=2时显然: (2)假设n=k时,结论成立,哈密顿 ...
- python基础===文件对象的访问模式,以及计数循环的使用方法
案例一: 一个几M的文本文件,需要每隔100行写到新的文件中. 代码实现如下: with open(r'f:\book.txt','rb') as f1: with open(r'f:\book2.t ...
- 两个kernel.org国内镜像
两个kernel.org国内镜像 https://mirror.tuna.tsinghua.edu.cn/kernel/v4.x/testing/ http://mirror.bjtu.edu.cn/ ...
- 配置iptables,把80端口转到8080
在Linux的下面部署了tomcat,为了安全我们使用非root用户进行启动,但是在域名绑定时无法直接访问80端口号.众所周知,在unix下,非root用户不能监听1024以上的端口号,这个tomca ...
- Python多线程常用包对比
python由于本身的特质,不能实现真正的多核并行运算,但是有一些第三方库较好地模拟了在多核环境下的并行运算,例如pp包以及multiprocessing,那么哪种更能充分利用多核心呢? 这里我简单做 ...
- golang命令行参数解析
package main import ( "fmt" "os" ) func main(){ s:= os.Args fmt.Println(s) } 直接执 ...
- Selenium2+python自动化57-捕获异常(NoSuchElementException)【转载】
前言 在定位元素的时候,经常会遇到各种异常,为什么会发生这些异常,遇到异常又该如何处理呢? 本篇通过学习selenium的exceptions模块,了解异常发生的原因. 一.发生异常 1.打开博客首页 ...