AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

聊一聊 C# 弱引用底層是怎么玩的

來源: 責編: 時間:2024-06-28 17:09:52 121觀看
導讀一、背景1. 講故事最近在分析dump時,發現有程序的卡死和WeakReference有關,在以前只知道怎么用,但不清楚底層邏輯走向是什么樣的,借著這個dump的契機來簡單研究下。二、弱引用的玩法1. 一些基礎概念用過WeakReference的朋

一、背景

1. 講故事

最近在分析dump時,發現有程序的卡死和WeakReference有關,在以前只知道怎么用,但不清楚底層邏輯走向是什么樣的,借著這個dump的契機來簡單研究下。ad328資訊網——每日最新資訊28at.com

二、弱引用的玩法

1. 一些基礎概念

用過WeakReference的朋友都知道這里面又可以分為弱短和弱長兩個概念,對應著構造函數中的trackResurrection參數,同時它也是對底層GCHandle.Alloc 方法的封裝,參考源碼如下:ad328資訊網——每日最新資訊28at.com

public WeakReference(object? target, bool trackResurrection){    Create(target, trackResurrection);}private void Create(object target, bool trackResurrection){    nint num = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);    _taggedHandle = (trackResurrection ? (num | 1) : num);    ComAwareWeakReference.ComInfo comInfo = ComAwareWeakReference.ComInfo.FromObject(target);    if (comInfo != null)    {        ComAwareWeakReference.SetComInfoInConstructor(ref _taggedHandle, comInfo);    }}public enum GCHandleType{    //    // Summary:    //     This handle type is used to track an object, but allow it to be collected. When    //     an object is collected, the contents of the System.Runtime.InteropServices.GCHandle    //     are zeroed. Weak references are zeroed before the finalizer runs, so even if    //     the finalizer resurrects the object, the Weak reference is still zeroed.    Weak = 0,    //    // Summary:    //     This handle type is similar to System.Runtime.InteropServices.GCHandleType.Weak,    //     but the handle is not zeroed if the object is resurrected during finalization.    WeakTrackResurrection = 1}

從上面的 GCHandleType 的注釋來看。ad328資訊網——每日最新資訊28at.com

  • Weak 會在終結器執行之前判斷持有的對象是否為垃圾對象,如果是的話直接切斷引用。
  • WeakTrackResurrection 會在終結器執行之后判斷對象是否為垃圾對象,如果是的話直接切斷引用。

可能這么說有點抽象,畫張圖如下:ad328資訊網——每日最新資訊28at.com

圖片圖片ad328資訊網——每日最新資訊28at.com

2. 一個簡單的測試例子

為了方便講述兩者的區別,使用 對象復活 來做測試。ad328資訊網——每日最新資訊28at.com

  • Weak 的情況

因為在 ScanForFinalization 方法之前做的判斷,所以與垃圾對象的聯系會被馬上切斷,參考代碼如下:ad328資訊網——每日最新資訊28at.com

class Program    {        static void Main()        {            WeakReferenceCase();            GC.Collect();            GC.WaitForPendingFinalizers();            Console.WriteLine(weakHandle.Target ?? "Person 引用被切斷");            Console.ReadLine();        }        public static GCHandle weakHandle;        static void WeakReferenceCase()        {            var person = new Person() { ressurect = false };            weakHandle = GCHandle.Alloc(person, GCHandleType.Weak);        }    }    public class Person    {        public bool ressurect = false;        ~Person()        {            if (ressurect)            {                Console.WriteLine("Person 被永生了,不可能被消滅的。。。");                GC.ReRegisterForFinalize(this);            }            else            {                Console.WriteLine("Person 析構已執行...");            }        }    }

圖片圖片ad328資訊網——每日最新資訊28at.com

  • WeakTrackResurrection 的情況

因為是在 ScanForFinalization 之后做的判斷,這時候可能會存在 對象復活 的情況,所以垃圾又變成不垃圾了,如果是這種情況就不能切斷,參考代碼如下:ad328資訊網——每日最新資訊28at.com

static void WeakReferenceCase(){    var person = new Person() { ressurect = true };    weakHandle = GCHandle.Alloc(person, GCHandleType.WeakTrackResurrection);}

圖片圖片ad328資訊網——每日最新資訊28at.com

3. coreclr源碼分析

在 coreclr 里有一個 struct 枚舉強對應 GCHandleType 結構體,而且名字看的更加清楚,代碼如下:ad328資訊網——每日最新資訊28at.com

typedef enum{ HNDTYPE_WEAK_SHORT = 0, HNDTYPE_WEAK_LONG = 1,}HandleType;

接下來看下剛才截圖源碼上的驗證。ad328資訊網——每日最新資訊28at.com

void gc_heap::mark_phase(int condemned_gen_number, BOOL mark_only_p){ // null out the target of short weakref that were not promoted. GCScan::GcShortWeakPtrScan(condemned_gen_number, max_generation, &sc); dprintf(3, ("Finalize marking")); finalize_queue->ScanForFinalization(GCHeap::Promote, condemned_gen_number, mark_only_p, __this); // null out the target of long weakref that were not promoted. GCScan::GcWeakPtrScan(condemned_gen_number, max_generation, &sc);}BOOL CFinalize::ScanForFinalization(promote_func* pfn, int gen, BOOL mark_only_p, gc_heap* hp){    for (unsigned int Seg = startSeg; Seg <= gen_segment(0); Seg++)    {        Object** endIndex = SegQueue(Seg);        for (Object** i = SegQueueLimit(Seg) - 1; i >= endIndex; i--)        {            CObjectHeader* obj = (CObjectHeader*)*i;            if (!g_theGCHeap->IsPromoted(obj))            {                if (method_table(obj)->HasCriticalFinalizer())                {                    MoveItem(i, Seg, CriticalFinalizerListSeg);                }                else                {                    MoveItem(i, Seg, FinalizerListSeg);                }            }        }    }    if(finalizedFound) GCToEEInterface::EnableFinalization(true);    return finalizedFound;}

源碼中有幾個注意點:ad328資訊網——每日最新資訊28at.com

  • 如何判斷一個對象為垃圾

gc 在標記時,將有根的對象mt的第一位設為 1 來表示當前已經標記過,即有用對象,未被標記的即為垃圾對象。ad328資訊網——每日最新資訊28at.com

  • 終結器線程真的被啟動了嗎

從簡化的源碼看,一旦有垃圾對象被送入到 終結器隊列的 預備區 時,就會通過 GCToEEInterface::EnableFinalization(true) 啟動終結器線程,所以在測試代碼中加了 GC.WaitForPendingFinalizers(); 就是為了等待終結器線程執行完畢然后才判斷 Target,這樣結果就會更加準確。ad328資訊網——每日最新資訊28at.com

4. 切斷邏輯在哪里

有些朋友會好奇那個 weakHandle.Target=null 的邏輯到底在 coreclr 的何處,這個比較簡單,可以用 windbg 下 ba 斷點即可,我們還是拿弱引用來舉例,截圖如下:ad328資訊網——每日最新資訊28at.com

圖片圖片ad328資訊網——每日最新資訊28at.com

三、總結

WeakReference 的內部玩法有很多,更深入的理解還需要對 g_HandleTableMap 進行深度挖掘,后面有機會再聊吧,有時候dump分析還是挺苦逼的,需要對相關領域底層知識有一個足夠了解,否則談何修復呢?ad328資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-97278-0.html聊一聊 C# 弱引用底層是怎么玩的

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 十個 Python 秘訣將顛覆你的編碼方式

下一篇: 為什么會 Js 但是依然不會寫 Node?原因竟是這三點...

標簽:
  • 熱門焦點
Top