dotnet ConditionalWeakTable 的底层原理
在 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 的底层原理的更多相关文章
- Neo4j图数据库简介和底层原理
现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘.NoSQL数据库的兴起,很好地解决了海 ...
- 【T-SQL进阶】02.理解SQL查询的底层原理
本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...
- spring框架的IOC的底层原理
1.IOC概念:spring容器创建对象并管理 2.IOC的底层原理的具体实现: 1)所使用的技术: (1). dom4j解析xml配置文件 (2).工厂设计模式(解耦合) (3).反射 第一步:配置 ...
- 深入研究Sphinx的底层原理和高级使用
深入研究Sphinx的底层原理和高级使用
- 深入研究Node.js的底层原理和高级使用
深入研究Node.js的底层原理和高级使用
- HashMap的底层原理
简单说: 底层原理就是采用数组加链表: 两张图片很清晰地表明存储结构: 既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现: // 存储时: int hash = ke ...
- 操作系统底层原理与Python中socket解读
目录 操作系统底层原理 网络通信原理 网络基础架构 局域网与交换机/网络常见术语 OSI七层协议 TCP/IP五层模型讲解 Python中Socket模块解读 TCP协议和UDP协议 操作系统底层原理 ...
- Servlet底层原理、Servlet实现方式、Servlet生命周期
Servlet简介 Servlet定义 Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. Servlet的特点 (1)Servlet对像,由Servlet容器 ...
- Spring Aop底层原理详解
Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)
- JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能
摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...
随机推荐
- 浅析三维模型3DTile格式轻量化处理常见问题与处理措施
浅析三维模型3DTile格式轻量化处理常见问题与处理措施 三维模型3DTile格式的轻量化处理是大规模三维地理空间数据可视化的关键环节,但在实际操作过程中,往往会遇到一些问题.下面我们来看一下这些常见 ...
- 新零售SaaS架构:线上商城系统架构设计
零售商家为什么要建设线上商城? 传统的实体门店服务范围有限,只能吸引周边500米以内的消费者.因此,如何拓展服务范围,吸引更多的消费者到店,成为了店家迫切需要解决的问题. 缺乏忠实顾客,客户基础不稳, ...
- C++设计模式 - 模板方法(Template Method)
组件协作模式: 现代软件专业分工之后的第一个结果是"框架与应用程序的划分","组件协作"模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用 ...
- C++设计模式 - 抽象工厂(Abstract Factory)
对象创建模式 通过"对象创建" 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 典型模式 Fac ...
- .Net接入AzureOpenAI、OpenAI、通义千问、智谱AI、讯飞星火、文心一言大语言模型。
前言 现在在网上搜索.NET接入大模型的帖子很少,有些官方案例只提供java和python的SDK,所以有了这篇.Net的接入大模型文章,目前仅实现对话模型的调用. 这里仅举例通义千问,其他模型实现可 ...
- #dp#洛谷 4158 [SCOI2009]粉刷匠
题目 分析 首先每条木板可以分开处理,再合并起来求最大值 下面讲一下单独处理每条木板的情况 设\(dp[k][m]\)表示前\(m\)个格子粉刷了\(k\)次最多正确粉刷的格子数 那么 \[dp[k] ...
- OpenHarmony开发者论坛正式上线,盖楼赢惊喜好礼~
你,是否曾遇到OpenHarmony开发难题,却不知找谁解答? 你,是否曾想分享OpenHarmony技术,但没有一个官方投稿平台? 你,是否想加入火热的OpenHarmony开源项目,却不知如何 ...
- 寻找OpenHarmony「锦鲤」|万元豪礼+技术干货全是你的!
开源项目 OpenHarmony 是每个人的 OpenHarmony 战"码"先锋第二期蓄力出发! 同时,我们也推出了全网寻找开源锦鲤的活动 只为每一位参与OpenHarmony开 ...
- Pandas统计计算
基本的统计方法 Method Description count Number of non-NA values describe Compute set of summary statistics ...
- RabbitMQ 08 路由模式
路由模式 路由模式结构图: 定义配置类. import org.springframework.amqp.core.Binding; import org.springframework.amqp.c ...