在 dotnet 中有一个特殊的类,这个类能够做到附加属性一样的功能。也就是给某个对象附加一个属性,当这个对象被回收的时候,自然解除附加的属性的对象的引用。本文就来聊聊这个类的底层原理

小伙伴都知道弱缓存是什么,弱缓存的核心是弱引用。也就是我虽然拿到一个对象,但是我没有给这个对象添加依赖引用,也就是这个对象不会记录被弱引用的引用。而 ConditionalWeakTable 也是一个弱缓存只是有些特殊的是关联的是其他对象。使用方法请看 .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary) - walterlv

这个类一般用来做弱缓存字典,只要 Key 没有被回收,而 value 就不会被回收。如果 key 被回收,那么 value 将会减去一个依赖引用。而字典对于 key 是弱引用

通过阅读 runtime 的源代码,可以看到实际上这个类的核心需要 DependentHandle 结构体的支持,因为依靠 key 定住 value 需要 CLR 的 GC 支持。什么是依靠 key 定住 value 的功能?这里的定住是 Pin 的翻译,意思是如果 key 存在内存,那么将会给 value 添加一个引用,此时的 value 将不会被回收。而如果 key 被回收了,此时的 value 将失去 key 对他的强引用

换句话说,只要 key 的值存在,那么 value 一定不会回收

这个功能纯使用 WeakReference 是做不到的,需要 GC 的支持,而在 dotnet core 里面提供 GC 支持的对接的是 DependentHandle 结构体

那么 DependentHandle 的功能又是什么?这个结构体提供传入 object primary, object? secondary 构造函数,作用就是当 primary 没有被回收的时候,给 secondary 添加一个引用计数。在 primary 回收的时候,解除对 secondary 的引用。而这个结构体本身对于 primary 是弱引用的,对于 secondary 仅在 primary 没有被回收时是强引用,当 primary 被回收之后将是弱引用

刚好利用 GC 的只要对象至少有一个引用就不会被回收的功能,就能做到 ConditionalWeakTable 提供附加属性的功能

下面代码是 DependentHandle 结构体的代码,可以看到大量的方法都是需要 GC 层的支持,属于 CLR 部分的注入方法

    internal struct DependentHandle
{
private IntPtr _handle; public DependentHandle(object primary, object? secondary) =>
// no need to check for null result: nInitialize expected to throw OOM.
_handle = nInitialize(primary, secondary); public bool IsAllocated => _handle != IntPtr.Zero; // Getting the secondary object is more expensive than getting the first so
// we provide a separate primary-only accessor for those times we only want the
// primary.
public object? GetPrimary() => nGetPrimary(_handle); public object? GetPrimaryAndSecondary(out object? secondary) =>
nGetPrimaryAndSecondary(_handle, out secondary); public void SetPrimary(object? primary) =>
nSetPrimary(_handle, primary); public void SetSecondary(object? secondary) =>
nSetSecondary(_handle, secondary); // Forces dependentHandle back to non-allocated state (if not already there)
// and frees the handle if needed.
public void Free()
{
if (_handle != IntPtr.Zero)
{
IntPtr handle = _handle;
_handle = IntPtr.Zero;
nFree(handle);
}
} [MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr nInitialize(object primary, object? secondary); [MethodImpl(MethodImplOptions.InternalCall)]
private static extern object? nGetPrimary(IntPtr dependentHandle); [MethodImpl(MethodImplOptions.InternalCall)]
private static extern object? nGetPrimaryAndSecondary(IntPtr dependentHandle, out object? secondary); [MethodImpl(MethodImplOptions.InternalCall)]
private static extern void nSetPrimary(IntPtr dependentHandle, object? primary); [MethodImpl(MethodImplOptions.InternalCall)]
private static extern void nSetSecondary(IntPtr dependentHandle, object? secondary); [MethodImpl(MethodImplOptions.InternalCall)]
private static extern void nFree(IntPtr dependentHandle);
}

而核心实现的入口是在 gchandletable.cpp 的 OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secondary) 代码,这部分属于更底的一层了,在功能上就是实现上面的需求,而实现上为了性能优化,代码可读性还是渣了一些

要实现这个功能需要在 GC 层里面写上一大堆的代码,但使用上现在仅有 ConditionalWeakTable 一个在使用

dotnet ConditionalWeakTable 的底层原理的更多相关文章

  1. Neo4j图数据库简介和底层原理

    现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘.NoSQL数据库的兴起,很好地解决了海 ...

  2. 【T-SQL进阶】02.理解SQL查询的底层原理

    本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...

  3. spring框架的IOC的底层原理

    1.IOC概念:spring容器创建对象并管理 2.IOC的底层原理的具体实现: 1)所使用的技术: (1). dom4j解析xml配置文件 (2).工厂设计模式(解耦合) (3).反射 第一步:配置 ...

  4. 深入研究Sphinx的底层原理和高级使用

    深入研究Sphinx的底层原理和高级使用

  5. 深入研究Node.js的底层原理和高级使用

    深入研究Node.js的底层原理和高级使用

  6. HashMap的底层原理

    简单说: 底层原理就是采用数组加链表: 两张图片很清晰地表明存储结构: 既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现: // 存储时: int hash = ke ...

  7. 操作系统底层原理与Python中socket解读

    目录 操作系统底层原理 网络通信原理 网络基础架构 局域网与交换机/网络常见术语 OSI七层协议 TCP/IP五层模型讲解 Python中Socket模块解读 TCP协议和UDP协议 操作系统底层原理 ...

  8. Servlet底层原理、Servlet实现方式、Servlet生命周期

    Servlet简介 Servlet定义 Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. Servlet的特点 (1)Servlet对像,由Servlet容器 ...

  9. Spring Aop底层原理详解

    Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)

  10. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

随机推荐

  1. 在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问题。

    在 PostgreSQL 中,bytea_output 参数控制在查询结果中 bytea 类型的显示格式.默认情况下,bytea_output 的值为 hex,这意味着在查询结果中,bytea 类型的 ...

  2. SPSS安装及破解教程

    SPSS是一种统计分析软件,其全称为"Statistical Product and Service Solutions".以下是SPSS的作用和好处: 作用: 数据管理:SPSS ...

  3. SMASH:经典One-Shot神经网络搜索,仅需单卡 | ICLR 2018

    SMASH方法使用辅助网络生成次优权重来支持网络的快速测试,从结果来看,生成的权重与正常训练的权重在准确率上存在关联性,整体搜索速度很快,仅需要单卡进行搜索,提供了一个很好的新思路.   来源:晓飞的 ...

  4. Kingbase ES 游标跨事务及其案例一则

    前言 本文介绍游标在PLSQL和SQL层跨事务使用案例,及其案例一则. 本文验证版本: db0=# select version(); db0-# / version ---------------- ...

  5. KingbaseES Json 系列十一:Json数组操作函数

    KingbaseES Json 系列十一--Json数组操作函数(JSONB_ARRAY_ELEMENTS,JSONB_ARRAY_ELEMENTS_TEXT,JSONB_ARRAY_LENGTH,J ...

  6. sys_stat_statements 扩展使用介绍

    sys_stat_statements 模块提供追踪服务器所执行的所有SQL语句的执行统计信息,可以用于统计数据库的资源开销,如分析TOP SQL. KingbaseES V8R6版本该插件已经内置化 ...

  7. 02 jQuery选择器

    02 jQuery选择器 jQuery的逻辑和css选择器的逻辑是一样的. // 语法: $(选择器) 可以使用jQuery选择器快速的对页面结构进行操作. 案例: <!DOCTYPE html ...

  8. 12 CSS 的float属性

    12 CSS 的float属性 流动布局 流动模型(Flow),即文档流,浏览器打开HTML网页时,从上往下,从左往右,逐一加载. 在正常情况下,HTML元素都会根据文档流来分布网页内容的. 文档流有 ...

  9. #dp,排列#LOJ 2743「JOI Open 2016」摩天大楼

    题目 将互不相同的 \(n\) 个数重排,使得相邻两数差的总和不超过 \(L\) 的有多少种方式. \(n\leq 100,L\leq 1000\) 分析 对于排列的问题,有一种很妙的方法就是从小到大 ...

  10. #DP#CF9D How many trees?

    题目 用\(n\)个点组成二叉树,问高度\(\geq h\)的有多少个. 分析 首先前缀和相减就能得到答案,做dp 设\(dp[n][h]\)表示节点数为\(n\),高度不超过\(h\)的树的个数 那 ...