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

C#.Net析构知识引申(CLR级的剖析)

来源: 责编: 时间:2023-10-13 14:37:19 198观看
导读一.前言析构函数是一个特殊的函数,它有自己的线程,有自己的实现方式。在CLR里面相当于一个小型的自我运转系统(有的书本把这个称之为终结器)。来看下一些概念以及一些运行模型。二.概述析构函数有一堆的概念
1.析构对

一.前言

析构函数是一个特殊的函数,它有自己的线程,有自己的实现方式。在CLR里面相当于一个小型的自我运转系统(有的书本把这个称之为终结器)。来看下一些概念以及一些运行模型。TMv28资讯网——每日最新资讯28at.com

二.概述

析构函数有一堆的概念
1.析构对象列表(也就是存放了包含析构函数的对象),它是最原始的。也就是当进行对象实例化分配的时候,会判断此对象是否包含了析构函数,如果包含了,则把此对象添加到析构对象列表。TMv28资讯网——每日最新资讯28at.com

flags & GC_ALLOC_FINALIZE

2.析构空闲列表(FreeList==7,也即是不允许被调用的析构函数所在的对象,这些对象存放在这个列表),它是C#里面一个著名的: GC.SuppressFinalize()来启用,以不允许CLR调用虚构函数。前提是首先这个对象里面包含了析构函数,然后才可以设置相应的标志位用以让CLR不执行此对象的析构函数。并且GC运行的时候也会需要这个对象没有存活才可以放入到析构空闲列表。TMv28资讯网——每日最新资讯28at.com

if (!obj->GetMethodTable ()->HasFinalizer())    return;//这里如果对象不包含析构函数,则直接返回,即使启用了GC.SuppressFinalize也毫无作用。GCHeapUtilities::GetGCHeap()->SetFinalizationRun(obj);//这里给ObjectHeader设置BIT_SBLK_FINALIZER_RUN标志,当GC进行扫描的时候,发现了这个标志,并且此对象没有被标记存活,那么此对象就放入到析构空闲列表

关于GC运行的时候也会需要判断这个对象没有存活才可以放入到析构空闲列表。TMv28资讯网——每日最新资讯28at.com

if (!g_theGCHeap->IsPromoted (obj))//GC运想需要判断此对象是否存活,不存活才可以进行下一步 {  //然后会判断是否包含了GC.SuppressFinalize设置的标志,如果包含,则表示此对象的析构函数不运行运行,把这个对象放入到空闲析构队列  if ((obj->GetHeader()->GetBits()) & BIT_SBLK_FINALIZER_RUN)  {    MoveItem (i, Seg, FreeList);//把对象移动到析构空闲队列    obj->GetHeader()->ClrBit (BIT_SBLK_FINALIZER_RUN);//清除GC.SuppressFinalize设置的标记}

3.关键析构函数列表堆(CriticalFinalizerListSeg==5这个队列目前的情况不是太明了,尚未弄清它是做什么的,先搁置)TMv28资讯网——每日最新资讯28at.com

4.析构列表堆(FinalizerListSeg==6,它存放的是需要被析构线程调用的析构函数所在的对象)TMv28资讯网——每日最新资讯28at.com

三.原理

了解了以上概念之后,我们来看下它这些队列的内存模型。首先要明确的一点是这些列表共用一个数组。CLR只是对这个数组进行骚操作,用以区分析构对对象列表,FreeList,CriticalFinalizerListSeg,FinalizerListSeg等四个队列。TMv28资讯网——每日最新资讯28at.com

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


图标里面缺少一个析构对象列表,那是因为析构对象列表页是跟它们共用一个地址,也即是m_FillPointers数组值0x100地址。TMv28资讯网——每日最新资讯28at.com

它们如何操作和分配呢?TMv28资讯网——每日最新资讯28at.com

1.当对象进行实例化的时候,把包含析构函数的对象添加到析构对象列.TMv28资讯网——每日最新资讯28at.com

2.当析构函数列表添加完毕之后,在进行GC垃圾回收的时候。在标记对象的动作里面也即是mark_phase里,会对析构对象列表进行扫描。扫描的时候会进行以下动作。
首先,会获取当前GC堆代的起始地址。从这个起始地址开始遍历循环到第三代结尾地址。在这个大循环前提下,里面有个小循环。小循环的作用是找出循环堆里面的析构对象列表。也即是图示的m_FillPointers数组的值。当找到析构对象列表,循环这个析构对象列表里面的对象,判断它是否存活,如果存活则不进行处理。如果不存活,则分情况。分别会移动到TMv28资讯网——每日最新资讯28at.com

FreeList,CriticalFinalizerListSeg,FinalizerListSeg等三个队列。
FreeList也即是析构空闲列表,它里面包含的对象的析构函数永远不会被调用。FinalizerListSeg里面包含了被调用的析构函数对象。CriticalFinalizerListSeg目的不明确,目前不清楚干什么。TMv28资讯网——每日最新资讯28at.com

3.当扫描完毕完毕析构对象列表之后,就会启动析构线程。析构线程会调用TMv28资讯网——每日最新资讯28at.com

FinalizerListSe列表和CriticalFinalizerListSe分别运行里面的析构函数。过程是:这个线程会判断索引6也即是FinalizerListSe和索引5是否相等,如果不相等。则表示有析构函数需要调用,把这个对象取出来,然后调用里面的析构函数。然后会判断索引5也即是TMv28资讯网——每日最新资讯28at.com

CriticalFinalizerListSe,跟FinalizerListSe同样的方式.TMv28资讯网——每日最新资讯28at.com

4.RegisterForFinalization(注册析构函数,也即是把有析构函数的对象放到析构列表)
ScanForFinalization(扫描析构列表,也即是区分关键析构列表堆,析构空闲列表等)
GetNextFinalizableObject(调用析构函数)TMv28资讯网——每日最新资讯28at.com

四.析构线程

析构线程用的是windows事件内核对象来操控的,这里举一个简单的例子TMv28资讯网——每日最新资讯28at.com

#include <stdio.h>#include <windows.h>#include <process.h>HANDLE g_hEvent;UINT __stdcall ChildFunc(LPVOID);int main(int argc, char* argv[]){  HANDLE hChildThread;  UINT uId;  // 创建一个自动重置的(auto-reset events),未受信的(nonsignaled)事件内核对象  g_hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);  hChildThread = (HANDLE)::_beginthreadex(NULL, 0, ChildFunc, NULL, 0, &uId);  // 通知子线程开始工作  printf("Please input a char to tell the Child Thread to work: /n");  getchar();  ::SetEvent(g_hEvent);  // 等待子线程完成工作,释放资源  ::WaitForSingleObject(hChildThread, INFINITE);  printf("All the work has been finished. /n");  ::CloseHandle(hChildThread);  ::CloseHandle(g_hEvent);  return 0;}UINT __stdcall ChildFunc(LPVOID){  ::WaitForSingleObject(g_hEvent, INFINITE);  printf("  Child thread is working...... /n");  ::Sleep(5*1000); // 暂停5秒,模拟真正的工作  return 0;}

SetEvent通知线程进行工作,那么析构线程呢,则是CLR在某个时间段通知其进行工作。具体的表现为,注册析构函数,扫描析构函数,这两步完成之后,就会通过SetEvent来通知析构线程,你可以进行工作了。此时析构线程就会从析构对象列表里面取出CriticalFinalizerListSe和FinalizerListSe来调用析构函数。TMv28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-13559-0.htmlC#.Net析构知识引申(CLR级的剖析)

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

上一篇: 使用 Spring Boot 和 Kafka Streams 进行实时数据处理

下一篇: 在 IDEA 中的各种调试技巧,轻松定位 Bug(超级全面)

标签:
  • 热门焦点
  • MIX Fold3包装盒泄露 新机本月登场

    MIX Fold3包装盒泄露 新机本月登场

    小米的全新折叠屏旗舰MIX Fold3将于本月发布,近日该机的真机包装盒在网上泄露。从图上来看,新的MIX Fold3包装盒在外观设计方面延续了之前的方案,变化不大,这也是目前小米旗舰
  • 6月iOS设备性能榜:M2稳居榜首 A系列只能等一手3nm来救

    6月iOS设备性能榜:M2稳居榜首 A系列只能等一手3nm来救

    没有新品发布,自然iOS设备性能榜的上榜设备就没有什么更替,仅仅只有跑分变化而产生的排名变动,毕竟苹果新品的发布节奏就是这样的,一年下来也就几个移动端新品,不会像安卓厂商,一
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • JavaScript 混淆及反混淆代码工具

    JavaScript 混淆及反混淆代码工具

    介绍在我们开始学习反混淆之前,我们首先要了解一下代码混淆。如果不了解代码是如何混淆的,我们可能无法成功对代码进行反混淆,尤其是使用自定义混淆器对其进行混淆时。什么是混
  • SpringBoot中使用Cache提升接口性能详解

    SpringBoot中使用Cache提升接口性能详解

    环境:springboot2.3.12.RELEASE + JSR107 + Ehcache + JPASpring 框架从 3.1 开始,对 Spring 应用程序提供了透明式添加缓存的支持。和事务支持一样,抽象缓存允许一致地使用各
  • 多线程开发带来的问题与解决方法

    多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 使用AIGC工具提升安全工作效率

    使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 阿里大调整

    阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 网红炒股不为了赚钱,那就是耍流氓!

    网红炒股不为了赚钱,那就是耍流氓!

    来源:首席商业评论6月26日高调宣布入市,网络名嘴大v胡锡进居然进军了股市。在一次财经媒体峰会上,几个财经圈媒体大佬就&ldquo;胡锡进炒股是否知道认真报道&rdquo;展开讨论。有
Top