有的时候,我们需要给某些数据添加一些附加信息,一种常用的做法是使用一个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表,。

使用.Net中的WeakDictionary — ConditionalWeakTable的更多相关文章

  1. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

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

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

  3. ASP.NET Core 中的 ObjectPool 对象重用(二)

    前言 上一篇文章主要介绍了ObjectPool的理论知识,再来介绍一下Microsoft.Extensions.ObjectPool是如何实现的. 核心组件 ObjectPool ObjectPool ...

  4. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  5. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  6. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  7. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  8. Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

    jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...

  9. 关于CryptoJS中md5加密以及aes加密的随笔

    最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...

随机推荐

  1. spring结合Mybatis的框架搭建(一)

    一:前沿 2015年新年上班的第二天,第一天就打了一天的酱油哦,只是下午开始搭建自己毕业设计的框架,搭建的是spring+spring mvc+MyBatis的框架.今天遇到了一个问题,结果弄了我一天 ...

  2. 数学:Lucas定理

    利用Lucas定理解决大组合数取模 Lucas定理是用来求 C(n,m) mod p,p为素数的值.(注意:p一定是素数) Lucas定理用来解决大组合数求模是很有用的 Lucas定理最大的数据处理能 ...

  3. Spring - IoC(1): Spring 容器

    BeanFactory & ApplicationContext org.springframework.beans.factory.BeanFactory 是最基本的 Spring 容器接口 ...

  4. syntax error near unexpected token `then'问题的解决

    http://blog.csdn.net/gongmin856/article/details/7690917 #!/bin/bash #if program test echo 'a:' read ...

  5. Java坦克大战 (二) 之画一个能动的圆圈代表坦克

    本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...

  6. [ Python - 5 ] 通过random模块生成随机字符串

    import random checkcode = '' for i in range(4): if i == random.randint(0,3): current = chr(random.ra ...

  7. Spring -- 注解事务 以及 7个传播行为

    注解事务: 1.开启注解事务配置: <!-- 事务管理器 --> <bean id="transactionManager" class="org.sp ...

  8. k8s的Rolling Update(滚动更新应用)

    滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新.滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 下面我们部署三副本应用: 初始 ...

  9. 《锋利的jQuery》读书要点笔记6——制作商城网页:结构和样式设计

    第8章 用jQuery打造个性网站 做一个购物网站并用jQuery来完善.大体步骤是: 收集素材 确定网站结构 A. 文件结构,imagea文件夹用来存放将要用到的图片,styles文件夹存放CSS, ...

  10. Eclipse默认标签TODO,XXX,FIXME和自定义标签

    1 TODO 表示需要实现,但目前还未实现的功能 2 XXX 勉强可以工作,但是需要改进的功能 3 FIXME 代码是错误的,不能工作,需要修复 4.自定义标签 window-->prefere ...