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

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

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

1.前言

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

2.概述

析构函数目前发现的总共有三个标记,这里分别一一介绍下。先上一段代码:Sk628资讯网——每日最新资讯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生成Sk628资讯网——每日最新资讯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实际上继承的是textreaderSk628资讯网——每日最新资讯28at.com

public class StreamReader : TextReader{}

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

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

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

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

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

GC.SuppressFinalize(this);

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

GC.SuppressFinalize

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

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

m_dwFlags |= enum_flag_HasFinalizer(0x00100000);

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

逻辑代码如下:Sk628资讯网——每日最新资讯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,则设置对象头。它的判断逻辑如下Sk628资讯网——每日最新资讯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.然后在对象分配的时候,把它放入到析构队列里面去。Sk628资讯网——每日最新资讯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,则不放入。Sk628资讯网——每日最新资讯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的最底层逻辑。当然这里还有很多技术问题需要解决。后面再看。Sk628资讯网——每日最新资讯28at.com

标记的作用

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

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

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

BIT_SBLK_FINALIZER_RUN标志,则表示此对象的析构队列里的对象可以移出了,也就是不运行此对象的析构函数。Sk628资讯网——每日最新资讯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在外观方面相比前两代有很大的变化,不再是小号的横向折叠屏,而是跟别的厂商一样采用了较为常见的
  • 7月安卓手机好评榜:三星S23Ultra好评率第一

    性能榜和性价比榜之后,我们来看最后的安卓手机好评榜,数据来源安兔兔评测,收集时间2023年7月1日至7月31日,仅限国内市场。第一名:三星Galaxy S23 Ultra好评率:95.71%在即将迎来新
  • 5月iOS设备性能榜:M1 M2依旧是榜单前五

    和上个月一样,没有新品发布的iOS设备性能榜的上榜设备并没有什么更替,仅仅只有跑分变化而产生的排名变动,刚刚开始的苹果WWDC2023,推出的产品也依旧是新款Mac Pro、新款Mac Stu
  • 企业采用CRM系统的11个好处

    客户关系管理(CRM)软件可以为企业提供很多的好处,从客户保留到提高生产力。  CRM软件用于企业收集客户互动,以改善客户体验和满意度。  CRM软件市场规模如今超过580
  • 大厂卷向扁平化

    来源:新熵作者丨南枝 编辑丨月见大厂职级不香了。俗话说,兵无常势,水无常形,互联网企业调整职级体系并不稀奇。7月13日,淘宝天猫集团启动了近年来最大的人力制度改革,目前已形成一
  • 三星折叠屏手机去年销售近1000万台 今年目标定为1500万

    7月29日消息,三星率先发力可折叠手机市场,在全球市场已经取得了非常亮眼的成绩,接下来会进一步巩固和扩大这一优势。三星在推出Galaxy Z Flip5和Galax
  • 三星电子Q2营收60万亿韩元 存储业务营收同比仍下滑超过50%

    7月27日消息,据外媒报道,从三星电子所发布的财报来看,他们主要利润来源的存储芯片业务在今年二季度仍不乐观,营收同比仍在大幅下滑,所在的设备解决方案
  • 质感不错!OPPO K11渲染图曝光:旗舰IMX890传感器首次下放

    一直以来,OPPO K系列机型都保持着较为均衡的产品体验,历来都是2K价位的明星机型,去年推出的OPPO K10和OPPO K10 Pro两款机型凭借各自的出色配置,堪称有
  • 世界人工智能大会国际日开幕式活动在世博展览馆开启

    30日上午,世界人工智能大会国际日开幕式活动在世博展览馆开启,聚集国际城市代表、重量级院士专家、国际创新企业代表,共同打造人工智能交流平台。上海市副市
Top