自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

.Net析構(gòu)函數(shù)再論(源碼剖析)

開(kāi)發(fā) 前端
一個(gè)對(duì)象需要進(jìn)行空間的分配,當(dāng)進(jìn)行空間分配的時(shí)候,它會(huì)判斷當(dāng)前函數(shù)是否包含了析構(gòu)函數(shù)。如果包含了,則設(shè)置flags標(biāo)志最后一位位1.然后在對(duì)象分配的時(shí)候,把它放入到析構(gòu)隊(duì)列里面去。

1.前言

本篇繼續(xù)看下析構(gòu)函數(shù)的一些引申知識(shí)。

2.概述

析構(gòu)函數(shù)目前發(fā)現(xiàn)的總共有三個(gè)標(biāo)記,這里分別一一介紹下。先上一段代碼:

internal class Program :  IDisposable{
     static void Main(string[] args){
         StreamReader? streamReader = null;
         streamReader = new StreamReader("Test_.dll");
         streamReader?.Dispose();
         Console.ReadLine();
     }
     ~Program(){
         Console.WriteLine("調(diào)用了析構(gòu)函數(shù)");
     }
     public void Dispose(){
         this.Dispose();
         GC.SuppressFinalize(this);
     }
 }

這里的析構(gòu)函數(shù)跟Dispose一起混用, ~Program()析構(gòu)函數(shù)會(huì)通過(guò)Roslyn生成

.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

這里同時(shí)需要注意 streamReader?.Dispose();這句話(huà),streamreader實(shí)際上繼承的是textreader

public class StreamReader : TextReader
{}

所以它調(diào)用Dispose的代碼是TextReader里面的Dispose:

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

也就是關(guān)閉了streamReader流。然后base.Dispose.這個(gè)base.Dispose實(shí)際上就是它的父類(lèi)TextReader里面的

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

Dispose里面的下面一句代碼

GC.SuppressFinalize(this);

它是重點(diǎn)。

GC.SuppressFinalize

1.判斷當(dāng)前類(lèi)是否有析構(gòu)函數(shù)

如果類(lèi)里面有析構(gòu)函數(shù),比如例子里的Program,則會(huì)設(shè)置MethodTable的成員m_dwFlags

m_dwFlags |= enum_flag_HasFinalizer(0x00100000);

它的設(shè)置邏輯是如果存在析構(gòu)函數(shù),并且當(dāng)前方法不是接口,不是虛方法,方法的索引小于當(dāng)前類(lèi)的索引數(shù),當(dāng)前的方法不是Object.Finlize()。那么說(shuō)明當(dāng)前這個(gè)類(lèi)有析構(gòu)函數(shù),所以需要在當(dāng)前類(lèi)的MethodTable上進(jìn)行操作,也即上面的m_dwFlags位設(shè)置。

邏輯代碼如下:

//存在析構(gòu)函數(shù),并且當(dāng)前方法不是接口,不是虛方法
if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass())
{
    WORD slot = g_pObjectFinalizerMD->GetSlot();
    //方法的索引小于當(dāng)前類(lèi)宗的索引數(shù),當(dāng)前的方法不是Object.Finlize()
    if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)
    {
        GetHalfBakedMethodTable()->SetHasFinalizer(); //這個(gè)地方就是設(shè)置m_dwFlags
        //此處省略一萬(wàn)行
    }
}

2.調(diào)用GC.SuppressFinalize

設(shè)置當(dāng)前類(lèi)的對(duì)象頭

headerobj|BIT_SBLK_FINALIZER_RUN當(dāng)我們調(diào)用GC.SuppressFinalize的時(shí)候,它會(huì)進(jìn)行判斷m_dwFlags或上的enum_flag_HasFinalizer位是否為1,如果位0直接返回,如果為1,則設(shè)置對(duì)象頭。它的判斷邏輯如下

if (!obj->GetMethodTable ()->HasFinalizer())//HasFinalizer函數(shù)判斷m_dwFlags的enum_flag_HasFinalizer位
return;
GCHeapUtilities::GetGCHeap()->SetFinalizationRun(obj);//這里設(shè)置當(dāng)前類(lèi)的對(duì)象頭headerobj|BIT_SBLK_FINALIZER_RUN
BIT_SBLK_FINALIZER_RUN定義如下:
#define BIT_SBLK_FINALIZER_RUN   0x40000000

3.對(duì)象進(jìn)行分配空間的時(shí)候

設(shè)置flags |= GC_ALLOC_FINALIZE一個(gè)對(duì)象需要進(jìn)行空間的分配,當(dāng)進(jìn)行空間分配的時(shí)候,它會(huì)判斷當(dāng)前函數(shù)是否包含了析構(gòu)函數(shù)。如果包含了,則設(shè)置flags標(biāo)志最后一位位1.然后在對(duì)象分配的時(shí)候,把它放入到析構(gòu)隊(duì)列里面去。

if (pMT->HasFinalizer())//判斷當(dāng)前類(lèi)是否包含析構(gòu)函數(shù)
    flags |= GC_ALLOC_FINALIZE;//如果包含則設(shè)置flags最后一位為1
GC_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,
};

當(dāng)進(jìn)行對(duì)象分配的時(shí)候,它會(huì)判斷falgs最后一位是否為1,如果為1,則把對(duì)象放入到析構(gòu)隊(duì)列,不為1,則不放入。

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的值,下面的邏輯如果對(duì)象為空直接返回,如果不為空則判斷flags & GC_ALLOC_FINALIZE是否等于1,如果為零直接返回,如果為1,則調(diào)用REGISTER_FOR_FINALIZATION,把對(duì)象放入析構(gòu)隊(duì)列
    if ((_object) == NULL || ((_register) && !REGISTER_FOR_FINALIZATION(_object, _size))) 
    {
        STRESS_LOG_OOM_STACK(_size);
        return NULL;
    }

以上是析構(gòu)函數(shù),GC.SuppressFinalize,Dispose的最底層邏輯。當(dāng)然這里還有很多技術(shù)問(wèn)題需要解決。后面再看。

標(biāo)記的作用

GC.SuppressFinalize問(wèn)題來(lái)了,它的這些標(biāo)記有什么用呢?這是一個(gè)非常繞的問(wèn)題,分析下。首先的enum_flag_HasFinalizer標(biāo)記表示當(dāng)前類(lèi)包含了析構(gòu)函數(shù),GC_ALLOC_FINALIZE標(biāo)記表示當(dāng)前的類(lèi)對(duì)象需要填充到析構(gòu)隊(duì)列里面去。

而B(niǎo)IT_SBLK_FINALIZER_RUN標(biāo)記是最為重要的,它如果被標(biāo)記了則表示從析構(gòu)隊(duì)列里面溢出,不需要運(yùn)行這個(gè)當(dāng)前類(lèi)的析構(gòu)函數(shù)。

在GC的標(biāo)記階段標(biāo)記對(duì)象是否存活完成之后,它需要對(duì)對(duì)象的析構(gòu)隊(duì)列進(jìn)行掃描。如果析構(gòu)隊(duì)列(SegQueue)里的對(duì)象被標(biāo)記存活,且它的對(duì)象頭有

BIT_SBLK_FINALIZER_RUN標(biāo)志,則表示此對(duì)象的析構(gòu)隊(duì)列里的對(duì)象可以移出了,也就是不運(yùn)行此對(duì)象的析構(gòu)函數(shù)。

//這里的ScanForFinalization是在GCScanRoot之運(yùn)行的,還有一個(gè)從析構(gòu)函數(shù)里面取出
//對(duì)象運(yùn)行析構(gòu)函數(shù)則是GCHeap::GetNextFinalizableObject
CFinalize::ScanForFinalization (promote_func* pfn, int gen, BOOL mark_only_p,
                                gc_heap* hp)
{   
  //判斷對(duì)象頭是否標(biāo)記了BIT_SBLK_FINALIZER_RUN
  if ((obj->GetHeader()->GetBits()) & BIT_SBLK_FINALIZER_RUN)
                    {
                        //如果標(biāo)記了,則把這個(gè)對(duì)象移除到FreeList,也即是空閑的析構(gòu)列表,不然存在于析構(gòu)列表中
                        MoveItem (i, Seg, FreeList);
                        //然后清除掉此對(duì)象頭BIT_SBLK_FINALIZER_RUN標(biāo)志
                        obj->GetHeader()->ClrBit (BIT_SBLK_FINALIZER_RUN);
                    }
}
再論CLR析構(gòu)函數(shù).net 6 析構(gòu)函數(shù)的幾個(gè)特性CLR析構(gòu)列表是如何添加析構(gòu)函數(shù)類(lèi)的
責(zé)任編輯:武曉燕 來(lái)源: 江湖評(píng)談
相關(guān)推薦

2023-10-11 14:18:40

C#.Net析構(gòu)

2021-12-11 19:02:03

函數(shù)C++對(duì)象

2009-08-14 17:24:28

C#構(gòu)造函數(shù)和析構(gòu)函數(shù)

2025-02-18 00:08:00

代碼C++RAII

2010-07-20 09:52:27

Perl構(gòu)造函數(shù)

2009-09-03 13:14:55

C#構(gòu)造函數(shù)C#析構(gòu)函數(shù)

2009-12-04 17:16:41

PHP析構(gòu)函數(shù)

2010-07-16 17:12:58

Perl析構(gòu)函數(shù)

2010-01-18 15:53:27

C++析構(gòu)函數(shù)

2010-02-04 16:39:26

C++析構(gòu)函數(shù)

2011-07-15 01:29:39

C++析構(gòu)函數(shù)

2009-07-30 15:24:13

C#析構(gòu)函數(shù)C#構(gòu)造函數(shù)

2024-12-19 14:42:15

C++內(nèi)存泄漏內(nèi)存管理

2010-02-05 13:35:19

C++虛析構(gòu)函數(shù)

2009-11-24 16:18:14

PHP5析構(gòu)函數(shù)

2009-09-02 10:49:46

C#調(diào)用析構(gòu)方法

2009-10-15 17:50:48

VB.NET調(diào)用API

2010-03-29 09:11:02

Python引用計(jì)數(shù)

2015-12-15 09:58:19

golang環(huán)境配置建議

2010-09-07 13:40:02

DIV標(biāo)簽
點(diǎn)贊
收藏

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