zoukankan      html  css  js  c++  java
  • C++随笔:.NET CoreCLR之GC探索(2)

      首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话,我以前也不看这些东西,只是因为自己觉得对C++感兴趣,索性乱写点东西,如果有写得不好的地方,还请上面2位大神指出。

      其实我现在虽然写的是C++,但是我打算在后面把C++和.NET的一些基础类库融合起来,我发现写CLR的文章特别少,不知道什么原因。反正,废话不多,开始今天的写作吧,今天依然是把重点集中在GC上面。

      首先跟大家分享一下我这次碰到的一个有趣的东西,就是下面的东西,下面的东西我第一次看,不过我可以确定的是,GC的运行模式有以下。以下都有注释,我就不详解了,不过跟大家说一下我的一个小小的发现:我猜测,以下代码只在64位GC下运行,这句话听起来很拗口,但是我是怎么得到这个结论的呢?

    // !!!!!!!!!!!!!!!!!!!!!!!
    // make sure you change the def in bclsystemgc.cs 
    // if you change this!
    //上面那句ENGLISH的意思就是如果要改这里面的值,必须先改变bc1systemgc.cs里面的定义
    //收集器运行模式
    enum collection_mode
    {
        collection_non_blocking = 0x00000001, //非锁定模式
        collection_blocking = 0x00000002,  //锁定模式
        collection_optimized = 0x00000004, //优化模式
        collection_compacting = 0x00000008 //最小适配模式
    
    #ifdef STRESS_HEAP //如果定义了Stress_heap,我这里翻译为压力堆,也就是“入堆”
        , collection_gcstress = 0x80000000 //这里我觉得应该是GC可以入堆的一个条件吧,虽然我不懂这个是什么意思
    #endif // STRESS_HEAP
    };
    

      

      虽然我不敢完全说我是对的,但是有一点可以确定,就是它会生成x64,以windows内核为寄托的一个以i结尾的文件,我们可以把它理解为一个临时文件,而GC和windows内存的关系就像一个寄宿关系一样,GC是依赖于windows内核的某个东西生存(全是个人的猜测)。

      那么,这些enmu类型的固定值,在GC当中,到底起了一个什么样的作用呢?我随便找了几个变量,因为这些固定值,其实在GC当中,你可以理解它是无处不在的,就相当于平常写代码的if else 一样普通,大家知道这些变量的用处就行了,不必过于纠结代码是什么意思,因为以后我会带大家慢慢研究。

    //如果定义成了后台GC
    #ifdef BACKGROUND_GC if (recursive_gc_sync::background_running_p()) { //如果mode(暂时可以理解为一个变量) //collection_non_blocking 值是0x00000001,也就是说mode&collection_non_blocking其实只要比较最右边一位就OK了,也就是mode=1 or 4 if ((mode == collection_optimized) || (mode & collection_non_blocking)) { return S_OK; } if (mode & collection_blocking) { pGenGCHeap->background_gc_wait(); if (mode & collection_optimized) { return S_OK; } } }

      今天我也不想过多的浪费时间,我打算挑一个有代表性的代码片段来带大家了解GC,所谓GC,GC是什么,那么它肯定有一个Collect的方法;好,那我们就拿这个方法开刀吧。首先我们必须知道几个知识点,对于非c++程序员来说,也还是需要学一点东西,size_t的解释,在这里简单一点说就是long unsigned  int ,我为什么特意把long标红呢?因为我们的GC使用的方法,是在64位环境下运行的,如果是32位的,那么就是unsigned int .

      因为这段代码很长,所以我打算:先讲一部分,然后再讲剩下的部分,不然大家就算看注释,也会眼花的。

    //函数返回值。如果这个函数是执行完返回的话将包含具有实际意义的数据,如果立即返回则包含状态信息--发送成功与否 -来自百度
    HRESULT
    
    //generation(代,比如你和你父母是2代人)
    //
    GCHeap::GarbageCollect (int generation, BOOL low_memory_p, int mode)
    {
    	//如果定义了64位的。。。也就是说,此GC的CLR是在64位运行时上跑的
    #if defined(BIT64) 
    
    	//如果定义了弱存储指针 PS:我也不知道怎么翻译,索性把low翻译成弱。
        if (low_memory_p)
        {
    		//1.初始化:所有已经分配的空间
            size_t total_allocated = 0;
    		//所有“想要”分配的空间
            size_t total_desired = 0;
    
    		//如果定义了复杂堆(我自己翻译的)
    #ifdef MULTIPLE_HEAPS
            int hn = 0;
    
    		//n_heaps这个定义我没找到,不过我可以确定的是,这个肯定是和MULTIPLE_HEAPS有关的
    		//大家可以把这个理解为MULTIPLE_HEAPS.Length
            for (hn = 0; hn < gc_heap::n_heaps; hn++)
            {
    			//首先是定义一个“临时”的指针hp,让gc堆当中的每一项都指向这个变量。
                gc_heap* hp = gc_heap::g_heaps [hn];
    			
    			//把每一块想要分配的数量,叠加起来。
                total_desired += dd_desired_allocation (hp->dynamic_data_of (0));
    
    			//总分配量=想要分配的-新分配的
                total_allocated += dd_desired_allocation (hp->dynamic_data_of (0))-
                    dd_new_allocation (hp->dynamic_data_of (0));
            }
    

      大家需要从上面的代码当中,掌握如下几个基础知识点:

      一个是dynamic_data_of方法,它返回了一个dynamic_data类的指针变量,那我们乘胜追击,看看这个方法和类。

        PER_HEAP
        dynamic_data* dynamic_data_of (int gen_number);
    

      首先是方法:

    //返回dynamic_data_table的第一个Table,大家可以类比.net中的DataSet
    inline
    dynamic_data* gc_heap::dynamic_data_of (int gen_number)
    {
        return &dynamic_data_table [ gen_number ];
    }
    

      然后我们再来看看这个dynamic_data_table,

        PER_HEAP
        dynamic_data dynamic_data_table [NUMBERGENERATIONS+1];
    

      下面来看这张图,突然我恍然大悟,所谓的DataTable,就是我们每次使用的DataSet,其实底层是放在堆栈上面的,以复杂堆的方式存放,而每个DataTable,其实就是堆栈当中的小小的组成而已,不止我理解得对不对。

    其中上面代码中的下面2个方法,都是和dynamic_data有关系的。其中ptrdiff_t类型变量通常用来保存两个指针减法操作的结果,这也是需要.NET程序员注意的,毕竟搞.NET是不和指针打交道的。

    inline
    size_t& dd_desired_allocation (dynamic_data* inst)
    {
      return inst->desired_allocation;
    }
    inline
    ptrdiff_t& dd_new_allocation (dynamic_data* inst)
    {
      return inst->new_allocation;
    }
    

      大家还要注意一下小细节,就是+=其实是先+=,再减去新分配的空间。

      今天就说这么多了,因为我还要做其他的事情,最后跟大家卖个关子,那些说.NET没技术含量的人,其实是不了解.NET原理的人。下面的就是一个比较复杂的类,这里面定义了超多的友元类,也就是说,GC表面上是一段代码,其实这就是一部重型航空母舰,需要我们去探索它的结构。

      爱因斯坦曾经说过一句名言:追求真理比占有真理更可贵。我们要做的,不仅仅是一颗螺丝钉。

  • 相关阅读:
    上传并压缩图片
    C#使用一般处理程序(ashx)中session
    cookie记住用户名密码
    操作数组
    鼠标滚轮事件兼容写法
    table嵌套table,jquery获取tr个数
    网站性能调优实战-学相伴KuangStudy
    为什么fdisk分区第一个分区以63或者2048扇区开始?
    oracle分组查询,获取组内所有信息(拼接显式)
    oracle中对象类型搜集(object type)
  • 原文地址:https://www.cnblogs.com/kmsfan/p/5499847.html
Copyright © 2011-2022 走看看