当前位置:首页 > 科技  > 软件

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

来源: 责编: 时间:2024-06-28 17:09:52 227观看
导读一、背景1. 讲故事最近在分析dump时,发现有程序的卡死和WeakReference有关,在以前只知道怎么用,但不清楚底层逻辑走向是什么样的,借着这个dump的契机来简单研究下。二、弱引用的玩法1. 一些基础概念用过WeakReference的朋

一、背景

1. 讲故事

最近在分析dump时,发现有程序的卡死和WeakReference有关,在以前只知道怎么用,但不清楚底层逻辑走向是什么样的,借着这个dump的契机来简单研究下。hXk28资讯网——每日最新资讯28at.com

二、弱引用的玩法

1. 一些基础概念

用过WeakReference的朋友都知道这里面又可以分为弱短和弱长两个概念,对应着构造函数中的trackResurrection参数,同时它也是对底层GCHandle.Alloc 方法的封装,参考源码如下:hXk28资讯网——每日最新资讯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 的注释来看。hXk28资讯网——每日最新资讯28at.com

  • Weak 会在终结器执行之前判断持有的对象是否为垃圾对象,如果是的话直接切断引用。
  • WeakTrackResurrection 会在终结器执行之后判断对象是否为垃圾对象,如果是的话直接切断引用。

可能这么说有点抽象,画张图如下:hXk28资讯网——每日最新资讯28at.com

图片图片hXk28资讯网——每日最新资讯28at.com

2. 一个简单的测试例子

为了方便讲述两者的区别,使用 对象复活 来做测试。hXk28资讯网——每日最新资讯28at.com

  • Weak 的情况

因为在 ScanForFinalization 方法之前做的判断,所以与垃圾对象的联系会被马上切断,参考代码如下:hXk28资讯网——每日最新资讯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 析构已执行...");            }        }    }

图片图片hXk28资讯网——每日最新资讯28at.com

  • WeakTrackResurrection 的情况

因为是在 ScanForFinalization 之后做的判断,这时候可能会存在 对象复活 的情况,所以垃圾又变成不垃圾了,如果是这种情况就不能切断,参考代码如下:hXk28资讯网——每日最新资讯28at.com

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

图片图片hXk28资讯网——每日最新资讯28at.com

3. coreclr源码分析

在 coreclr 里有一个 struct 枚举强对应 GCHandleType 结构体,而且名字看的更加清楚,代码如下:hXk28资讯网——每日最新资讯28at.com

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

接下来看下刚才截图源码上的验证。hXk28资讯网——每日最新资讯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;}

源码中有几个注意点:hXk28资讯网——每日最新资讯28at.com

  • 如何判断一个对象为垃圾

gc 在标记时,将有根的对象mt的第一位设为 1 来表示当前已经标记过,即有用对象,未被标记的即为垃圾对象。hXk28资讯网——每日最新资讯28at.com

  • 终结器线程真的被启动了吗

从简化的源码看,一旦有垃圾对象被送入到 终结器队列的 预备区 时,就会通过 GCToEEInterface::EnableFinalization(true) 启动终结器线程,所以在测试代码中加了 GC.WaitForPendingFinalizers(); 就是为了等待终结器线程执行完毕然后才判断 Target,这样结果就会更加准确。hXk28资讯网——每日最新资讯28at.com

4. 切断逻辑在哪里

有些朋友会好奇那个 weakHandle.Target=null 的逻辑到底在 coreclr 的何处,这个比较简单,可以用 windbg 下 ba 断点即可,我们还是拿弱引用来举例,截图如下:hXk28资讯网——每日最新资讯28at.com

图片图片hXk28资讯网——每日最新资讯28at.com

三、总结

WeakReference 的内部玩法有很多,更深入的理解还需要对 g_HandleTableMap 进行深度挖掘,后面有机会再聊吧,有时候dump分析还是挺苦逼的,需要对相关领域底层知识有一个足够了解,否则谈何修复呢?hXk28资讯网——每日最新资讯28at.com

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

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 十个 Python 秘诀将颠覆你的编码方式

下一篇: 为什么会 Js 但是依然不会写 Node?原因竟是这三点...

标签:
  • 热门焦点
  • 把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 企业采用CRM系统的11个好处

    客户关系管理(CRM)软件可以为企业提供很多的好处,从客户保留到提高生产力。  CRM软件用于企业收集客户互动,以改善客户体验和满意度。  CRM软件市场规模如今超过580
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 重估百度丨“晚熟”的百度云,能等到春天吗?

    &copy;自象限原创作者|程心排版|王喻可2016年7月13日,百度云计算战略发布会在北京举行,宣告着百度智能云的正式启程。彼时的会场座无虚席,甚至排队排到了门外,在场的所有人几乎都
  • 慕岩炮轰抖音,百合网今何在?

    来源:价值研究所 作者:Hernanderz&ldquo;难道就因为自己的一个产品牛逼了,从客服到总裁,都不愿意正视自己产品和运营上的问题,选择逃避了吗?&rdquo;这一番话,出自百合网联合创
  • 消息称小米汽车开始筛选交付中心:需至少120个车位

    IT之家 7 月 7 日消息,日前,有微博简介为“汽车行业从业者、长三角一体化拥护者”的微博用户 @长三角行健者 发文表示,据经销商集团反馈,小米汽车目前
  • 自研Exynos回归!三星Galaxy S24系列将提供Exynos和骁龙双版本

    年初,全新的三星Galaxy S23系列发布,包含Galaxy S23、Galaxy S23+和Galaxy S23 Ultra三个版本,全系搭载超频版骁龙8 Gen 2,虽同样采用台积电4nm工艺制
  • 电博会与软博会实现"线下+云端"的双线融合

    在本次“电博会”与“软博会”双展会利好条件的加持下,既可以发挥展会拉动人流、信息流、资金流实现快速交互流动的作用,继而推动区域经济良性发展;又可以聚
  • 亲历马斯克血洗Twitter,硅谷的苦日子在后头

    文/刘哲铭  编辑/李薇  马斯克再次挥下裁员大刀。  美国时间11月14日,Twitter约4400名外包员工遭解雇,此次被解雇的员工的主要工作为内容审核等。此前,T
Top