前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.Net8 PreView的析构函数再叙

.Net8 PreView的析构函数再叙

作者头像
江湖评谈
发布2023-11-13 20:27:05
1080
发布2023-11-13 20:27:05
举报
文章被收录于专栏:天下风云天下风云

1.前言 N久之前搞过析构方面的问题,但是前几天又遇到了这个问题。本篇来巩固下析构方面的知识,包括初始化析构管理类,析构队列添加数据,以及调用析构函数。以下以.Net8 PreView为蓝本发掘,友情提示:C++和C#混合开发,慎入。

2.概述 先上例子:

代码语言:javascript
复制
internal class Program{
    static void Main(string[] args){
        Program pm = new Program();
        pm = null;
        GC.Collect();
    }
    ~Program() {
        Console.WriteLine("调用了析构函数");
    }
}

初始化析构管理类

以上代码有一个~Program析构函数。CLR会在启动的时候初始化析构管理类

代码语言:javascript
复制
HRESULT AllocateCFinalize(CFinalize **pCFinalize)
{
    *pCFinalize = new (nothrow) CFinalize();
    if (*pCFinalize == NULL || !(*pCFinalize)->Initialize())
        return E_OUTOFMEMORY;

    return S_OK;
}

变量pCFinalize里面包含了指针填充数组m_FillPointers。

代码语言:javascript
复制
PTR_PTR_Object m_FillPointers[total_generation_count + ExtraSegCount]; //m_FillPointers[7]

它是一个object* 指针对象,长度是7.它的值填充的是析构队列的首地址,m_Array。也即是(* pCFinalize)->Initialize())调用填充。

简略图构

析构队列添加数据 上面初始化了析构管理类之后,就是往析构队列里面添加数据了。数据添加非常简单

代码语言:javascript
复制
CHECK_ALLOC_AND_POSSIBLY_REGISTER_FOR_FINALIZATION(newAlloc, size, flags & GC_ALLOC_FINALIZE);

flags & GC_ALLOC_FINALIZE,可以看到flags标志&上析构标志,判断当前对象newAlloc是否添加到析构队列。

填充析构队列的主要代码:

代码语言:javascript
复制
Object*** s_i = &SegQueue (FreeList); //Freelist==7
Object*** end_si = &SegQueueLimit (dest);//dest == 4
do
{
    if (!(*s_i == *(s_i-1))) //获取指针填充数据的第七个索引值和第六个索引值,判断是否不相等。
    {
        *(*s_i) = *(*(s_i-1)); //如果不相等就把指针填充数据第六个索引值所对应的对象赋值给第七个索引值对应的对象
    }
    (*s_i)++;//如果相等,继续下面的。这里把第7索引值+8,也就是析构队列的指针移动八位
    s_i--;//这里把指针填充数据的指针向前挪动八位
} while (s_i > end_si);//判断是否到底了,也就是dest==4的地方。
**s_i = obj;//如果到底了,把有析构函数的对象添加到析构队列。
(*s_i)++;//因为这个地址已经添加过了,所以需要下一个地址,这里++

以上动用了三级指针,横跨了析构管理类,指针填充数据,以及最终存放的对象。

调用析构函数 调用析构是异步执行模型,它在初始化完毕析构管理类之后就开始被启动。

代码语言:javascript
复制
coreclr.dll!FinalizerThread::FinalizeAllObjects()
ntdll.dll!RtlUserThreadStart()

FinalizeAllObjects()主要代码如下:

代码语言:javascript
复制
void FinalizerThread::FinalizeAllObjects()
{
    Object* fobj = GCHeapUtilities::GetGCHeap()->GetNextFinalizable();
    Thread *pThread = GetThread();
    while (fobj && !fQuitFinalizer)
    {
        fcount++;
        CallFinalizer(fobj);
        pThread->InternalReset();
        fobj = GCHeapUtilities::GetGCHeap()->GetNextFinalizable();
    }
    FireEtwGCFinalizersEnd_V1(fcount, GetClrInstanceId());
}

它会判断从析构队列里面取出的对象是否为空,不为空就调用这个对象的析构函数CallFinalizer。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-09-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江湖评谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档