有的时候,我们需要给某些数据添加一些附加信息,一种常用的做法是使用一个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的键值对,它满足如下需求:

  1. 字典中保存着Key的弱引用,即使不释放Key值,也可以被GC回收。
  2. 字典中保存的Value的强引用,Key没有被GC回收前,Value不会被GC回收。
  3. 当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数据能释放了,但是并不完善,具体体现在如下方面:

  1. Tag保存的仍然是强引用,得不到释放
  2. 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

使用.Net中的WeakDictionary — ConditionalWeakTable相关推荐

  1. .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 )...

    如果你使用过 WPF/UWP 等 XAML UI 框架,那么应该了解到附加属性的概念.那么没有依赖属性支持的时候如何做附加属性的功能呢?你可能会想到弱引用.但这需要做一个弱引用字典,要写的代码还是非常 ...

  2. GNU Make 使用手册(于凤昌中译版)

    GNU Make 使用手册(中译版) 翻译:于凤昌 GNU make Version 3.79 April 2000 Richard M. Stallman and Roland McGrath 1 ...

  3. 面试:第十二章:所有总结

    Java基础 java基本类型哪些,所占字节 byte :1个字节 short :2个字节 char :2个字节 int :4个字节 long :8个字节 float :4个字节 double :8个 ...

  4. linux内核分析(转自某位大哥网上的笔记)

    启动 当PC启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码.BIOS先进行一系列的系统自检,然后初始化位于地址0的中断 ...

  5. [转载] .NET 中可以有类似 JVM 的幻像引用吗?

    近日发现一篇不错的文章,文中列举了一些 GC 场景,探讨了 在 .NET 中是需要实现像 JVM 的中的幻像引用.有人质疑其不切实际,也有像 Ayende 大神一言不合就自己做了个 demo. Do ...

  6. golang通过RSA算法生成token,go从配置文件中注入密钥文件,go从文件中读取密钥文件,go RSA算法下token生成与解析;go java token共用

    RSA算法 token生成与解析 本文演示两种方式,一种是把密钥文件放在配置文件中,一种是把密钥文件本身放入项目或者容器中. 下面两种的区别在于私钥公钥的初始化, init方法,需要哪种取哪种. 通过 ...

  7. 总结一下在使用某里云服务器的过程中出现过的一些问题

    此文总结在使用阿里云的过程中出现过的问题   想起来就记录一下 本人为言行负责! 海内选择腾讯华为,共勉! k8s不同命名空间的配置文件串掉了 k8s集群服务器购买上后,无法使用外网.连续购买了4台然 ...

  8. Kubernetes 中 设置pod不部署在同一台节点上

    在k8s中,节点的调度主要由亲和性和污点来进行控制的.   而在亲和性部分由分为了节点亲和性和节点反亲和性.   节点亲和性是指在pod部署时,尽量(软策略)或者必须满足(硬策略)部署在某些节点上. ...

  9. 在Dockerfile中设置G1垃圾回收器参数

    在Dockerfile中设置G1垃圾回收器参数 ENV JAVA_OPTS="\ -server \ -XX:SurvivorRatio=8 \ -XX:+DisableExplicitGC ...

最新文章

  1. Windows下安装Z3的Python3版
  2. 大学物理光学思维导图_思维导图走进新华百货现代物流
  3. 6、oracle数据库下查询操作
  4. python矩阵中找满足条件的元素_Python 找到列表中满足某些条件的元素方法
  5. jquery实现html表格隔行变色
  6. 黑猫论坛实战免杀教程
  7. 洛谷3678:简单的数学题(画柿子+杜教筛)
  8. 洛谷1156 垃圾陷阱
  9. figma的一些用法(一)
  10. 电信卡 LTE 无法短信发送
  11. Python 模拟键盘鼠标操作实战教程
  12. 01-图灵商城项目架构
  13. 甲方和乙方怎么区别?
  14. Ubuntu 安装中文man手册
  15. 汇编语言零基础入门学习教程
  16. 最新php代码iP授权,网站授权加密源码授权源码PHP源码加密授权验证全新自带加密功能,域名+IP+时间...
  17. lisp提取长方形坐标_如何利用lisp程序一次性提取CAD中点的坐标(不要点击每个点,太多了麻烦)...
  18. 网易全面复盘直播答题,剖析产品架构的难点与坑
  19. 伺服增益参数简述及其调整
  20. 学习python,北京尚学堂,第31课到第60课的个人的总结

热门文章

  1. Flutter GetX 状态管理 响应式编程(三)
  2. Flutter Duration详细概述
  3. Android音乐播放器高级开发
  4. Mr.J--JavaScript-恶搞小代码
  5. kindeditor 4 指定生成文件的时间日期/动态获取My97的时间
  6. IOS修改webView背景透明以及IOS调用前台js的方法
  7. java枚举类型转换为Struts2的select的数据
  8. 用户和组 win2003
  9. Vue「五」—— 动态组件、插槽、自定义指令
  10. 7-66 计算工资 (15 分)