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

.Net析构函数再论(源码剖析)

来源: 责编: 时间:2023-10-10 18:31:51 339观看
导读1.前言本篇继续看下析构函数的一些引申知识。2.概述析构函数目前发现的总共有三个标记,这里分别一一介绍下。先上一段代码:internal class Program : IDisposable{ static void Main(string[] args){ Stre

1.前言

本篇继续看下析构函数的一些引申知识。FEj28资讯网——每日最新资讯28at.com

2.概述

析构函数目前发现的总共有三个标记,这里分别一一介绍下。先上一段代码:FEj28资讯网——每日最新资讯28at.com

internal class Program :  IDisposable{     static void Main(string[] args){         StreamReader? streamReader = null;         streamReader = new StreamReader("Test_.dll");         streamReader?.Dispose();         Console.ReadLine();     }     ~Program(){         Console.WriteLine("调用了析构函数");     }     public void Dispose(){         this.Dispose();         GC.SuppressFinalize(this);     } }

这里的析构函数跟Dispose一起混用, ~Program()析构函数会通过Roslyn生成FEj28资讯网——每日最新资讯28at.com

.method family hidebysig virtual instance void         Finalize() cil managed{  .override [System.Runtime]System.Object::Finalize  // 代码大小       24 (0x18)  .maxstack  1  IL_0000:  nop  .try  {    IL_0001:  nop    IL_0002:  ldstr      bytearray (03 8C 28 75 86 4E 90 67 84 67 FD 51 70 65 )       // ..(u.N.g.g.Qpe    IL_0007:  call       void [System.Console]System.Console::WriteLine(string)    IL_000c:  nop    IL_000d:  leave.s    IL_0017  }  // end .try  finally{    IL_000f:  ldarg.0    IL_0010:  call       instance void [System.Runtime]System.Object::Finalize()    IL_0015:  nop    IL_0016:  endfinally  }  // end handler  IL_0017:  ret} // end of method Program::Finalize

这里同时需要注意 streamReader?.Dispose();这句话,streamreader实际上继承的是textreaderFEj28资讯网——每日最新资讯28at.com

public class StreamReader : TextReader{}

所以它调用Dispose的代码是TextReader里面的Dispose:FEj28资讯网——每日最新资讯28at.com

public void Dispose() {     Dispose(true);     GC.SuppressFinalize(this); }

也就是关闭了streamReader流。然后base.Dispose.这个base.Dispose实际上就是它的父类TextReader里面的FEj28资讯网——每日最新资讯28at.com

public void Dispose(){   this._streamReader.close();}

Dispose里面的下面一句代码FEj28资讯网——每日最新资讯28at.com

GC.SuppressFinalize(this);

它是重点。FEj28资讯网——每日最新资讯28at.com

GC.SuppressFinalize

1.判断当前类是否有析构函数

如果类里面有析构函数,比如例子里的Program,则会设置MethodTable的成员m_dwFlagsFEj28资讯网——每日最新资讯28at.com

m_dwFlags |= enum_flag_HasFinalizer(0x00100000);

它的设置逻辑是如果存在析构函数,并且当前方法不是接口,不是虚方法,方法的索引小于当前类的索引数,当前的方法不是Object.Finlize()。那么说明当前这个类有析构函数,所以需要在当前类的MethodTable上进行操作,也即上面的m_dwFlags位设置。FEj28资讯网——每日最新资讯28at.com

逻辑代码如下:FEj28资讯网——每日最新资讯28at.com

//存在析构函数,并且当前方法不是接口,不是虚方法if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass()){    WORD slot = g_pObjectFinalizerMD->GetSlot();    //方法的索引小于当前类宗的索引数,当前的方法不是Object.Finlize()    if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)    {        GetHalfBakedMethodTable()->SetHasFinalizer(); //这个地方就是设置m_dwFlags        //此处省略一万行    }}

2.调用GC.SuppressFinalize

设置当前类的对象头

headerobj|BIT_SBLK_FINALIZER_RUN当我们调用GC.SuppressFinalize的时候,它会进行判断m_dwFlags或上的enum_flag_HasFinalizer位是否为1,如果位0直接返回,如果为1,则设置对象头。它的判断逻辑如下FEj28资讯网——每日最新资讯28at.com

if (!obj->GetMethodTable ()->HasFinalizer())//HasFinalizer函数判断m_dwFlags的enum_flag_HasFinalizer位return;GCHeapUtilities::GetGCHeap()->SetFinalizationRun(obj);//这里设置当前类的对象头headerobj|BIT_SBLK_FINALIZER_RUNBIT_SBLK_FINALIZER_RUN定义如下:#define BIT_SBLK_FINALIZER_RUN   0x40000000

3.对象进行分配空间的时候

设置flags |= GC_ALLOC_FINALIZE一个对象需要进行空间的分配,当进行空间分配的时候,它会判断当前函数是否包含了析构函数。如果包含了,则设置flags标志最后一位位1.然后在对象分配的时候,把它放入到析构队列里面去。FEj28资讯网——每日最新资讯28at.com

if (pMT->HasFinalizer())//判断当前类是否包含析构函数    flags |= GC_ALLOC_FINALIZE;//如果包含则设置flags最后一位为1GC_ALLOC_FINALIZE定义如下:enum GC_ALLOC_FLAGS{    GC_ALLOC_NO_FLAGS           = 0,    GC_ALLOC_FINALIZE           = 1,    GC_ALLOC_CONTAINS_REF       = 2,    GC_ALLOC_ALIGN8_BIAS        = 4,    GC_ALLOC_ALIGN8             = 8,    GC_ALLOC_ZEROING_OPTIONAL   = 16,    GC_ALLOC_LARGE_OBJECT_HEAP  = 32,    GC_ALLOC_PINNED_OBJECT_HEAP = 64,    GC_ALLOC_USER_OLD_HEAP      = GC_ALLOC_LARGE_OBJECT_HEAP | GC_ALLOC_PINNED_OBJECT_HEAP,};

当进行对象分配的时候,它会判断falgs最后一位是否为1,如果为1,则把对象放入到析构队列,不为1,则不放入。FEj28资讯网——每日最新资讯28at.com

CHECK_ALLOC_AND_POSSIBLY_REGISTER_FOR_FINALIZATION(newAlloc, size, flags & GC_ALLOC_FINALIZE); //flags & GC_ALLOC_FINALIZE判断falgs最后一位是否为1.#define CHECK_ALLOC_AND_POSSIBLY_REGISTER_FOR_FINALIZATION(_object, _size, _register) do {    //这里的register就是flags & GC_ALLOC_FINALIZE的值,下面的逻辑如果对象为空直接返回,如果不为空则判断flags & GC_ALLOC_FINALIZE是否等于1,如果为零直接返回,如果为1,则调用REGISTER_FOR_FINALIZATION,把对象放入析构队列    if ((_object) == NULL || ((_register) && !REGISTER_FOR_FINALIZATION(_object, _size)))     {        STRESS_LOG_OOM_STACK(_size);        return NULL;    }

以上是析构函数,GC.SuppressFinalize,Dispose的最底层逻辑。当然这里还有很多技术问题需要解决。后面再看。FEj28资讯网——每日最新资讯28at.com

标记的作用

GC.SuppressFinalize问题来了,它的这些标记有什么用呢?这是一个非常绕的问题,分析下。首先的enum_flag_HasFinalizer标记表示当前类包含了析构函数,GC_ALLOC_FINALIZE标记表示当前的类对象需要填充到析构队列里面去。

而BIT_SBLK_FINALIZER_RUN标记是最为重要的,它如果被标记了则表示从析构队列里面溢出,不需要运行这个当前类的析构函数。FEj28资讯网——每日最新资讯28at.com

在GC的标记阶段标记对象是否存活完成之后,它需要对对象的析构队列进行扫描。如果析构队列(SegQueue)里的对象被标记存活,且它的对象头有FEj28资讯网——每日最新资讯28at.com

BIT_SBLK_FINALIZER_RUN标志,则表示此对象的析构队列里的对象可以移出了,也就是不运行此对象的析构函数。FEj28资讯网——每日最新资讯28at.com

//这里的ScanForFinalization是在GCScanRoot之运行的,还有一个从析构函数里面取出//对象运行析构函数则是GCHeap::GetNextFinalizableObjectCFinalize::ScanForFinalization (promote_func* pfn, int gen, BOOL mark_only_p,                                gc_heap* hp){     //判断对象头是否标记了BIT_SBLK_FINALIZER_RUN  if ((obj->GetHeader()->GetBits()) & BIT_SBLK_FINALIZER_RUN)                    {                        //如果标记了,则把这个对象移除到FreeList,也即是空闲的析构列表,不然存在于析构列表中                        MoveItem (i, Seg, FreeList);                        //然后清除掉此对象头BIT_SBLK_FINALIZER_RUN标志                        obj->GetHeader()->ClrBit (BIT_SBLK_FINALIZER_RUN);                    }}
再论CLR析构函数 6 析构函数的几个特性CLR析构列表是如何添加析构函数类的

本文链接:http://www.28at.com/showinfo-26-12734-0.html.Net析构函数再论(源码剖析)

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

上一篇: Docker容器化构建可扩展的分布式缓存系统:Memcached和Redis

下一篇: 喝了100杯酱香拿铁,我开窍了

标签:
  • 热门焦点
  • Find N3入网:最高支持16+1TB

    OPPO将于近期登场的Find N3折叠屏目前已经正式入网,型号为PHN110。本次Find N3在外观方面相比前两代有很大的变化,不再是小号的横向折叠屏,而是跟别的厂商一样采用了较为常见的
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • 5月iOS设备性能榜:M1 M2依旧是榜单前五

    和上个月一样,没有新品发布的iOS设备性能榜的上榜设备并没有什么更替,仅仅只有跑分变化而产生的排名变动,刚刚开始的苹果WWDC2023,推出的产品也依旧是新款Mac Pro、新款Mac Stu
  • 梁柱接棒两年,腾讯音乐闯出新路子

    文丨田静 出品丨牛刀财经(niudaocaijing)7月5日,企鹅FM发布官方公告称由于业务调整,将于9月6日正式停止运营,这意味着腾讯音乐长音频业务走向消亡。腾讯在长音频领域还在摸索。为
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 携众多高端产品亮相ChinaJoy,小米带来一场科技与人文的视听盛宴

    7月28日,全球数字娱乐领域最具知名度与影响力的年度盛会中国国际数码互动娱乐展览会(简称ChinaJoy)在上海新国际博览中心盛大开幕。作为全球领先的科
  • 机构称Q2国内智能手机销量同比下滑4% vivo份额重回第1

    7月29日消息,根据市场调查机构Counterpoint Research公布的最新报告,2023年第2季度中国智能手机销量同比下降4%,创新自2014年以来第2季度销量新低。报
  • OPPO K11搭载长寿版100W超级闪充:26分钟充满100%

    据此前官方宣布,OPPO将于7月25日也就是今天下午14:30举办新品发布会,届时全新的OPPO K11将正式与大家见面,将主打旗舰影像,和同档位竞品相比,其最大的卖
  • 由于成本持续增加,笔记本产品价格预计将明显上涨

    根据知情人士透露,由于材料、物流等成本持续增加,笔记本产品价格预计将在2021年下半年有明显上涨。进入6月下旬以来,全球半导体芯片缺货情况加剧,显卡、处理器
Top