dotnet 6 使用 DependentHandle 关联对象生命周期
本文将告诉大家在 dotnet 6 新加入的 System.Runtime.DependentHandle 的类型的使用方法,通过 DependentHandle 可以实现将某个对象的引用生命周期和另一个对象关联起来
如 DependentHandle 结构体的构造函数,要传入两个对象作为参数,这两个对象参数分别是 target 和 dependent 参数对象,表示的意义是将这两个对象通过 DependentHandle 结构体建立关联。让 target 对象关联上 dependent 对象的生命周期,在 dependent 对象没有被释放之前,不会先释放 target 对象。功能上和 ConditionalWeakTable 差不多,只是 DependentHandle 作为 ConditionalWeakTable 的底层实现支持,直接使用 DependentHandle 可以有更多的控制
原本咱可以使用 ConditionalWeakTable 将对象进行关联,实现到将某个对象关联到另一个对象的生命周期上,只要另一个对象没有被释放,那么关联的对象也不会被释放。如此可以在不改动原有代码的前提下,让两个毫不关联的对象进行关联。例如可以用来实现缓存模块的功能
然而 ConditionalWeakTable 算是一个上层的封装,如果想要做更多的定制功能,那就可以采用在 dotnet 6 新加入的 System.Runtime.DependentHandle 结构体。这个结构体提供的是一对一的关联关系,而且可以方便调用 Dispose 方法解除关联性
接下来将写一个例子来告诉大家 DependentHandle 类型的使用方法
新建一个 WPF 项目,在界面放三个按钮,分别是进入断点按钮,用于进入断点看对象是否被释放。释放引用按钮,将关联的对象释放引用。由于在 .NET 里面,释放引用不代表立刻被回收,再加上一个 GC 按钮,用来点击的时候触发 GC 逻辑
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="10,10,10,10" />
</Style>
</StackPanel.Resources>
<Button Click="Button_Click">
进入断点
</Button>
<Button x:Name="FreeObjectButton" Click="FreeObjectButton_Click">
释放引用
</Button>
<Button x:Name="GCButton" Click="GCButton_Click">
GC
</Button>
</StackPanel>
在后台代码里面定义 Foo1 和 Foo2 两个类型,定义类型的用途是在于方便在内存里面找到这两个类型的对象
public class Foo1
{
}
public class Foo2
{
}
这两个类型没有相互关联性,在 MainWindow 添加一个 Foo1 类型的字段,如此即可让 Foo1 类型的对象被 MainWindow 引用,不会被释放
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var foo1 = new Foo1();
_foo1 = foo1;
}
private Foo1? _foo1;
如果在 MainWindow_Loaded 方法里面,创建一个 Foo2 对象,而让这个对象没有地方引用,那自然很快就会 Foo2 对象就会被释放
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var foo1 = new Foo1();
new Foo2();
_foo1 = foo1;
}
如果将 Foo2 通过 DependentHandle 实现和 Foo1 关联,加入到关联列表里面,如以下逻辑,将可以让 Foo2 不会被释放
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var foo1 = new Foo1();
HandleList.Add(new DependentHandle(foo1, new Foo2()));
_foo1 = foo1;
}
private List<DependentHandle> HandleList { get; } = new List<DependentHandle>();
假如 DependentHandle 是另外的某些类型,对 Foo2 的对象也有强引用关系,那自然 Foo2 不会被释放,只是不会被释放的理由是被 HandleList 给引用。但本文告诉大家的 DependentHandle 是不会对 Foo2 有强引用的,只是对 Foo2 关联 Foo1 对象
实现释放引用按钮的功能,点击按钮,将 Foo1 的对象引用释放,如此即可让 Foo1 的对象可以被回收
private void FreeObjectButton_Click(object sender, RoutedEventArgs e)
{
_foo1 = null;
}
由于在 .NET 里面,不会立刻回收,实现 GC 按钮的功能,手动触发回收
private void GCButton_Click(object sender, RoutedEventArgs e)
{
GC.Collect();
GC.WaitForFullGCComplete();
}
实现断点按钮的逻辑
private void Button_Click(object sender, RoutedEventArgs e)
{
Debugger.Break();
}
运行代码,先点击一下释放按钮,让 _foo 释放引用,接着点击 GC 按钮触发回收逻辑。多次点击 GC 按钮,等待一下,然后点击进入断电按钮,自己打上断点,通过 VS 的内存调试,可以看到 Foo1 和 Foo2 对象都没有存在内存里面
同时在 HandleList 列表里面,可以看到有一个 DependentHandle 对象,但是此对象里面的 Target 和 Dependent 都是 null 空对象
这就是证明了,通过 DependentHandle 可以建立从 Target 到 Dependent 的引用关联,在 Dependent 被回收之前,不会回收 Target 对象。在 Dependent 被回收之后,才会回收 Target 对象
在经过测试,使用 DependentHandle 的回收速度是比较慢的,很多时候,不是第一次点击 GC 按钮进行回收就能回收掉 Foo1 和 Foo2 对象的,而是需要多次点击
使用 dotnet 6 加入的 DependentHandle 进行底层的控制,更好写出符合自己业务逻辑的对象关联逻辑。例如实现自己的缓存库等。这个 Dependent 的功能是需要 CLR 层面提供的,也就是说这个类型只能在 dotnet 6 和更高版本使用,详细请看 dotnet ConditionalWeakTable 的底层原理
更多请看 DependentHandle Struct (System.Runtime) Microsoft Docs
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 8378751cc0766bc804fa8a1ae5ef3e0766dd5b99
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 8378751cc0766bc804fa8a1ae5ef3e0766dd5b99
获取代码之后,进入 LemjallbabelyeeburKemkubejer 文件夹
dotnet 6 使用 DependentHandle 关联对象生命周期的更多相关文章
- Hibernate的三种状态及对象生命周期
理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...
- .Net组件程序设计之对象生命周期
.Net组件程序设计之对象生命周期 .NET 垃圾回收 IDisposable() Using语句 .NET 垃圾回收 是CLR管理着垃圾回收器,垃圾回收器监控着托管堆,而我们使用的对象以及系统启动是 ...
- Ninject之旅之三:Ninject对象生命周期
摘要 DI容器的一个责任是管理他创建的对象的生命周期.他应该决定什么时候创建一个给定类型的对象,什么时候使用已经存在的对象.他还需要在对象不需要的时候处理对象.Ninject在不同的情况下管理对象的生 ...
- iOS视图控制对象生命周期
iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...
- IOS 视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途
iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...
- 【转】【iOS知识学习】_视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途
原文网址:http://blog.csdn.net/weasleyqi/article/details/8090373 iOS视图控制对象生命周期-init.viewDidLoad.viewWillA ...
- _视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途
iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...
- ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理
在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ...
- Python学习手册之内部方法、操作符重载和对象生命周期
在上一篇文章中,我们介绍了 Python 的类和继承,现在我们介绍 Python 的内部方法.操作符重载和对象生命周期. 查看上一篇文章请点击:https://www.cnblogs.com/dust ...
- Servlet对象生命周期(四)
一.Servlet对象生命周期 一下图片说明上图第7点 destroy()方法是在停止tomcat服务器时执行 https://pan.baidu.com/s/1mgTabWW#list/path=% ...
随机推荐
- Android保存多张图片到本地
目录介绍 01.实际开发保存图片遇到的问题 02.直接用http请求图片并保存本地 03.用glide下载图片保存本地 04.如何实现连续保存多张图片 05.关于其他介绍 好消息 博客笔记大汇总[16 ...
- 性能测试系列:Jmeter使用记录
jmeter配置环境变量vi /etc/profileexport PATH=$PATH:/tmp/jmeter/apache-jmeter-5.4.1/binsource /etc/profile ...
- 一周内容分享(第 10 期):别让自己"墙"了自己
这里记录过去一周,我看到的值得分享的东西. 一方面是整理记录一下自己一周的学习,另一方面也是期待自己有更多的输出,有更多的价值. 周刊开源(Github:wmyskxz/weekly),欢迎提交 is ...
- 记一次 .NET某防伪验证系统 崩溃分析
一:背景 1. 讲故事 昨晚给训练营里面的一位朋友分析了一个程序崩溃的故障,因为看小伙子昨天在群里问了一天也没搞定,干脆自己亲自上阵吧,抓取的dump也是我极力推荐的用 procdump 注册 AED ...
- KingbaseES V8R6集群运维案例之---repmgrd进程启动无法访问共享内存
案例说明: KingbaseES V8R6集群在启动repmgrd进程时,出现'unable to write to shared memory'故障,导致repmgrd进程启动终止. 适用版本: K ...
- P图神器Lama下载介绍,一键移除图片中任何不想要的元素
Lama是一个完全自托管的图像处理工具,基于最前沿的AIGC模型,它可以从图片中删除任何不需要的物体.缺陷或对象,却看不到一点修改痕迹~ 在以前,我们想将图片中的文字.水印去除,可以使用ps,但ps的 ...
- SpaceDesk怎么连接平板/PC(提高生产力,扩展副屏)
1.下载安装 分为安卓端和PC端,两个设备都需要安装对应的软件. SpaceDesk官网 https://link.zhihu.com/?target=http%3A//spacedesk.net/ ...
- #dp#洛谷 3244 [HNOI2015]落忆枫音
题目 分析 每个有入度的点可以选择任意一个父节点组成一棵树,那么原来的答案就是 \(\prod_{i=2}^ndeg[i]\) 现在多了一条边,如果边的终点是1或者它是一个自环那么可以不用管这条边. ...
- 前端常用库 CDN
jQuery 链接: v1.9.1:https://i.mazey.net/lib/jquery/1.9.1/jquery.min.js v2.1.1:https://i.mazey.net/lib/ ...
- OpenHarmony Docker移植实践
Docker简介 从操作系统诞生之日起,虚拟化技术就不断的演进与发展,结合目前云原生的发展态势,容器无疑是其中的重要一环. Docker是一个开源的软件项目,可以在Linux操作系统上提供一层额外的 ...