成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開(kāi)發(fā) 前端
WeakReference 的內(nèi)部玩法有很多,更深入的理解還需要對(duì) g_HandleTableMap 進(jìn)行深度挖掘,后面有機(jī)會(huì)再聊吧,有時(shí)候dump分析還是挺苦逼的,需要對(duì)相關(guān)領(lǐng)域底層知識(shí)有一個(gè)足夠了解,否則談何修復(fù)呢?

一、背景

1. 講故事

最近在分析dump時(shí),發(fā)現(xiàn)有程序的卡死和WeakReference有關(guān),在以前只知道怎么用,但不清楚底層邏輯走向是什么樣的,借著這個(gè)dump的契機(jī)來(lái)簡(jiǎn)單研究下。

二、弱引用的玩法

1. 一些基礎(chǔ)概念

用過(guò)WeakReference的朋友都知道這里面又可以分為弱短和弱長(zhǎng)兩個(gè)概念,對(duì)應(yīng)著構(gòu)造函數(shù)中的trackResurrection參數(shù),同時(shí)它也是對(duì)底層GCHandle.Alloc 方法的封裝,參考源碼如下:

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 的注釋來(lái)看。

  • Weak 會(huì)在終結(jié)器執(zhí)行之前判斷持有的對(duì)象是否為垃圾對(duì)象,如果是的話直接切斷引用。
  • WeakTrackResurrection 會(huì)在終結(jié)器執(zhí)行之后判斷對(duì)象是否為垃圾對(duì)象,如果是的話直接切斷引用。

可能這么說(shuō)有點(diǎn)抽象,畫(huà)張圖如下:

圖片圖片

2. 一個(gè)簡(jiǎn)單的測(cè)試?yán)?/h3>

為了方便講述兩者的區(qū)別,使用 對(duì)象復(fù)活 來(lái)做測(cè)試。

  • Weak 的情況

因?yàn)樵?ScanForFinalization 方法之前做的判斷,所以與垃圾對(duì)象的聯(lián)系會(huì)被馬上切斷,參考代碼如下:

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 析構(gòu)已執(zhí)行...");
            }
        }
    }

圖片圖片

  • WeakTrackResurrection 的情況

因?yàn)槭窃?ScanForFinalization 之后做的判斷,這時(shí)候可能會(huì)存在 對(duì)象復(fù)活 的情況,所以垃圾又變成不垃圾了,如果是這種情況就不能切斷,參考代碼如下:

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

圖片圖片

3. coreclr源碼分析

在 coreclr 里有一個(gè) struct 枚舉強(qiáng)對(duì)應(yīng) GCHandleType 結(jié)構(gòu)體,而且名字看的更加清楚,代碼如下:

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

接下來(lái)看下剛才截圖源碼上的驗(yàn)證。

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;
}

源碼中有幾個(gè)注意點(diǎn):

  • 如何判斷一個(gè)對(duì)象為垃圾

gc 在標(biāo)記時(shí),將有根的對(duì)象mt的第一位設(shè)為 1 來(lái)表示當(dāng)前已經(jīng)標(biāo)記過(guò),即有用對(duì)象,未被標(biāo)記的即為垃圾對(duì)象。

  • 終結(jié)器線程真的被啟動(dòng)了嗎

從簡(jiǎn)化的源碼看,一旦有垃圾對(duì)象被送入到 終結(jié)器隊(duì)列的 預(yù)備區(qū) 時(shí),就會(huì)通過(guò) GCToEEInterface::EnableFinalization(true) 啟動(dòng)終結(jié)器線程,所以在測(cè)試代碼中加了 GC.WaitForPendingFinalizers(); 就是為了等待終結(jié)器線程執(zhí)行完畢然后才判斷 Target,這樣結(jié)果就會(huì)更加準(zhǔn)確。

4. 切斷邏輯在哪里

有些朋友會(huì)好奇那個(gè) weakHandle.Target=null 的邏輯到底在 coreclr 的何處,這個(gè)比較簡(jiǎn)單,可以用 windbg 下 ba 斷點(diǎn)即可,我們還是拿弱引用來(lái)舉例,截圖如下:

圖片圖片

三、總結(jié)

WeakReference 的內(nèi)部玩法有很多,更深入的理解還需要對(duì) g_HandleTableMap 進(jìn)行深度挖掘,后面有機(jī)會(huì)再聊吧,有時(shí)候dump分析還是挺苦逼的,需要對(duì)相關(guān)領(lǐng)域底層知識(shí)有一個(gè)足夠了解,否則談何修復(fù)呢?

責(zé)任編輯:武曉燕 來(lái)源: 一線碼農(nóng)聊技術(shù)
相關(guān)推薦

2025-01-10 08:15:22

C#異步底層

2024-08-26 14:46:57

2021-03-29 00:02:10

C#Attribute元素

2024-12-26 10:05:58

C#前臺(tái)線程

2023-03-05 18:40:39

iptables防火墻軟件

2021-06-29 08:45:55

邏輯變量法函數(shù)

2022-08-30 07:39:57

C++namespace隔離

2023-10-24 15:56:23

2020-10-30 07:11:31

C 語(yǔ)言編程

2024-10-08 10:55:04

2023-12-07 07:26:04

2022-11-02 08:51:01

2024-01-02 13:26:39

TLSC#線程

2020-10-23 07:00:00

C++函數(shù)

2020-09-08 06:54:29

Java Gradle語(yǔ)言

2023-07-06 13:56:14

微軟Skype

2018-03-22 10:36:15

未來(lái)數(shù)據(jù)中心停機(jī)

2018-06-07 13:17:12

契約測(cè)試單元測(cè)試API測(cè)試

2023-09-22 17:36:37

2021-01-28 22:31:33

分組密碼算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 99精品国产一区二区三区 | 国产在线观看一区二区 | 久久草视频| 日韩一二三区 | 国产精品久久久久久亚洲调教 | 在线午夜| www成人啪啪18| 亚洲精品乱码久久久久久久久 | 国产视频亚洲视频 | 亚洲激情网站 | 亚洲成av人片在线观看无码 | 亚洲一区中文字幕 | 免费性视频 | 秋霞在线一区 | 中文无吗 | 国产一区2区 | 国产精品日韩 | 天天干夜夜操 | 午夜精品久久久久久久久久久久久 | 人人做人人澡人人爽欧美 | 国产 日韩 欧美 制服 另类 | 久久精品一级 | 国产资源在线视频 | 黄色网址在线免费观看 | 久久久久久国 | 在线亚州| 久久久人成影片免费观看 | 在线视频一区二区 | www.久久.com | 三级黄色片在线 | 成人av在线网站 | 日韩午夜 | 国产成人精品一区二区三 | 国产九一精品 | 日日夜夜狠狠操 | 日韩一区二区三区在线视频 | 国产一级黄色网 | 亚洲视频在线播放 | 国产成人免费在线 | 美女一级毛片 | 国产精品久久九九 |