• C++随笔:.NET CoreCLR之GC探索(1)


      一直是.NET程序员,但是.NET的核心其实还是C++,所以我准备花 一点时间来研究CoreCLR和CoreFX.希望这个系列的文章能给大家带来 帮助。

      GC的代码有很多很多,而且结构层次对于一个初学者来说,很难很快或者很慢掌握,所以我的建议是,抓住一段功能,到实际当中去看。本来想从开头 跟大家讲的,但是看 开头也是乱的,反正也没有多少经验,索性随便讲。

    //返回第二个参数seg的直接前驱节点
    heap_segment* heap_segment_prev (heap_segment* begin, heap_segment* seg)
    {
    	//判断是否begin指针指向了NULL
        assert (begin != 0);
    
    	//定义一个局部的变量,让第一个参数begin指向这个局部的指针。
        heap_segment* prev = begin;
    
    	//首先得到以begin为基准的下一个堆片段的地址
        heap_segment* current = heap_segment_next (begin);
    
    	//循环判断“下一个”地址是不是和函数的第二个参数的地址是指向同一块内存
        while (current && current != seg)
        {
    		//把得到的current当前的地址临时指向prev
            prev = current;
    		//去尝试得到下一个地址
            current = heap_segment_next (current);
        }
    
    	//上一个循环结束,如果当前segment等于形参,返回上一个
        if (current == seg)
        {
            return prev;
        }
    	//如果当前segment是头结点,那么没有直接前驱,返回空
        else
        {
            return 0;
        }
    }
    

      

    注意这里的heap_segment是类名,定义在gcpriv.h中,heap_segment_prev是方法的名称。heap_segment,我的理解其实很简单,就是 “堆的集合”,集合当中的每个元素,就是它的一个segment,每个元素是链式连接的。

    让我们来看看这个类的真容吧,这很重要,要注意它们的类型很多 都是Uint8_t,那么 这个结构体有什么特点呢?按照posix标准,一般整形对应的*_t类型为:

           1字节     uint8_t
           2字节     uint16_t
           4字节     uint32_t
           8字节     uint64_t

    由此我们可以得到一个很重要的信息,它们存放的片段都是 以一个字节为原子的,为什么会用这种方式去存储,这个我也不得而知。

    class heap_segment
    {
    public:
        uint8_t*        allocated; //已经分配的空间
        uint8_t*        committed; //已经被提交的
        uint8_t*        reserved; //已经被存储的
        uint8_t*        used; //已经被使用的
        uint8_t*        mem;  //空间
        size_t          flags; //标记
        PTR_heap_segment next; //下一个堆的片段
        uint8_t*        plan_allocated; //“将要” 分配的空间
    	//如果BACKGROUND_GC被定义的话,执行如下代码(后台GC)
    #ifdef BACKGROUND_GC
        uint8_t*        background_allocated; //后台分配
        uint8_t*        saved_bg_allocated; //已经保存的后台分配
    #endif //BACKGROUND_GC
    
    	//多个堆(不止是一个堆)
    #ifdef MULTIPLE_HEAPS
        gc_heap*        heap;   //这个类毕竟复杂,以后会专门抽出章节来说
    #endif //MULTIPLE_HEAPS
    
    #ifdef _MSC_VER
    // Disable this warning - we intentionally want __declspec(align()) to insert padding for us
    #pragma warning(disable:4324)  // structure was padded due to __declspec(align())
    #endif
        aligned_plug_and_gap padandplug;
    #ifdef _MSC_VER
    #pragma warning(default:4324)  // structure was padded due to __declspec(align())
    #endif
    };

    其中我来 解释一下PTR_heap_segment,它其实是一个自定义类型

    typedef DPTR(class heap_segment)               PTR_heap_segment;
    

    下面我们再回到heap_segment_prev这个方法,如果你能看懂我下面画的这幅图,你就应该能理解这个方法到底要干什么了。其实意图很明显,我们可以把heap看成是一个链表,暂时我们 不知道这个链表到底是什么链表,这个并不重要,重要的是,我们首先必须知道我们要从哪个节点开始,然后要寻找哪一个节点,就是分别对应下图的第一个参数和第二个参数,首先我们会进入一个while循环,如果我们第一次得到的不为NULL而且得到的heap的下一个节点(segment)不和第二个参数吻合,至于怎么吻合?就是2个地址是不是指指向同一块内存!直到找到为止,返回这个heap指定位置的前置节点。

      heap_segment_next 这个函数,我们看到,其实是指向heap_segment的下一个heap,并作为地址返回。

    inline
    PTR_heap_segment & heap_segment_next (heap_segment* inst)
    {
      return inst->next;
    }
    

      下面我们再来 看一下heap_segment_in_range这个函数。我们 先看看它的定义。

    inline
    BOOL heap_segment_in_range_p (heap_segment* inst)
    {
    	//它返回一个bool类型,当然此BOOL是自定义的	
        return (!(inst->flags & heap_segment_flags_readonly) ||
                ((inst->flags & heap_segment_flags_inrange) != 0));
    }
    

      当然我们 必须知道一个基本的定义,下面变量是里面本身定义好的。

    #define heap_segment_flags_readonly     1
    #define heap_segment_flags_inrange      2
    

      由此可以推断,heap_segment_in_range_p为True.

    下面我们来看这个方法,注释我已经打上了,但是我表示怀疑,为什么检测边界要通过这种一个一个链式的方式去检测,这样我们 就要把整个链表跑一次,真的有点怀疑这是不是最好的方法。

    //检查堆的边界,即最后一个元素
    heap_segment* heap_segment_in_range (heap_segment* ns)
    {
    	//这里是否会执行,决定于heap_segment的一些特性(我还不知道,所以不乱说)
        if ((ns == 0) || heap_segment_in_range_p (ns))
        {
            return ns;
        }
        else
        {
            do
            {
    			//这段代码其实是一个循环,它的作用是检测堆的一个“右边”边界
                ns = heap_segment_next (ns);
            } while ((ns != 0) && !heap_segment_in_range_p (ns));
            return ns;
        }
    }
    

      今天还想写的,不过很晚了,不然明天上班又起不来了。。。。先睡觉,晚安。  

  • 相关阅读:
    判别式模型与生成式模型
    C#和Excel进行报表开发
    C# TreeView序列化、串行化、反序列化
    磁盘碎片整理后电脑盘损坏的修复过程
    用C#实现CS模式下软件自动在线升级
    win10家庭版更改为企业版和激活
    [原创]前端页面检查神器google chrome lighthouse
    [原创] PDMReaderSetup下载
    SpringBoot定时任务@EnableScheduling
    【spring bean】@Resource注解的自动注入策略 , 以 项目中注入多个线程池的Bean为例 附加自定义SpringBeanSupport
  • 原文地址:https://www.cnblogs.com/kmsfan/p/5496628.html
Copyright © 2020-2023  润新知