本文將告訴大家在 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="https://www.cnblogs.com/lindexi/p/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
以上的代碼放在github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 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 檔案夾
博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/499694.html
標籤:.NET Core
上一篇:C#-陣列和動態陣列
