dotnet ConditionalWeakTable 的底層原理

来源:https://www.cnblogs.com/lindexi/archive/2020/06/16/13139054.html
-Advertisement-
Play Games

在 dotnet 中有一個特殊的類,這個類能夠做到附加屬性一樣的功能。也就是給某個對象附加一個屬性,當這個對象被回收的時候,自然解除附加的屬性的對象的引用。本文就來聊聊這個類的底層原理 ...


在 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 一個在使用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言:我們有時常會用到JObject對象接受數據,並通過JObject快速獲取指定key的值,順序的話是沒有問題的,但是假如你遇到如下的JObject對象,該怎麼快速獲取數據呢? { "details": { "threeds2.fingerprint": "123" }, "paymentData ...
  • 《Entity Framework 實用精要》 [作者] (中) 呂高旭[出版] 清華大學出版社[版次] 2018年01月 第1版[印次] 2018年01月 第1次 印刷[定價] 79.00元 【第01章】 (P011) 在 Entity Framework 的環境下,應用程式與實體數據模型進行溝通 ...
  • 近期有很多人找過來說,一些常見的開票意思不知道什麼意思,所以這邊特別整理了下常見的錯誤提示及解決方法,供大家參考。如需要瞭解其它,可查看其它文章 錯誤代碼 錯誤信息 解決方法YC0008 無清卡信息! 可能原因:已經完成清卡。YC0007 無上報彙總信息,請先執行上報彙總! 可能原因:未執行上報彙總 ...
  • 以下是WPF中的常見事件彙總表(按字母排序),翻譯不見得準確,但希望對你有用。 事件描述 Annotation.AnchorChanged 新增、移除或修改 Anchor 元素時發生。 Annotation.AuthorChanged 新增、移除或修改 Author 元素時發生。 Annotatio ...
  • 系列文章 基於 abp vNext 和 .NET Core 開發博客項目 - 使用 abp cli 搭建項目 基於 abp vNext 和 .NET Core 開發博客項目 - 給項目瘦身,讓它跑起來 基於 abp vNext 和 .NET Core 開發博客項目 - 完善與美化,Swagger登場 ...
  • 學習js:1.htmml2.cssjs+html+css == html5 js的組成:1).ecamscript ES是js的標準,js 是es 的實現2)文檔對象模型(Document Object Model,簡稱DOM)3)瀏覽器對象模型(Browser Object Model,簡稱BOM ...
  • 泛型的本質是類型參數化或參數化類型,在不創建新的類型的情況下,通過泛型指定的不同類型來控制形參具體限制的類型。 泛型是 2.0 版 C# 語言和 公共語言運行庫 (CLR) 中的一個新 功能。泛型將類型參數的概念引入 .NET Framework,類型參數使得設計如下類和方法成為可能:這些類和方法將 ...
  • 小伙伴都知道在 Windows 下是支持文件名使用分號的,而寫過 Roslyn 的小伙伴都知道,在 csproj 項目裡面使用分號分割數組。那麼在 VS 裡面將一個文件名添加分號會如何?下麵讓咱寫寫看 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...