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;
    }
}

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

时间: 2024-10-03 23:01:07

C++随笔:.NET CoreCLR之GC探索(1)的相关文章

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

今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder // for collected free space. // //初始化释放器(对象方法表),<-不知道翻译得对不对. //GC使用一

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

首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话,我以前也不看这些东西,只是因为自己觉得对C++感兴趣,索性乱写点东西,如果有写得不好的地方,还请上面2位大神指出. 其实我现在虽然写的是C++,但是我打算在后面把C++和.NET的一些基础类库融合起来,我发现写CLR的文章特别少,不知道什么原因.反正,废话不多,开始今天的写作吧,今天依然是把重点集中

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

有几天没写GC相关的文章了哈,今天我讲GC的方式是通过一个小的Sample来讲解,这个小的示例代码只有全部Build成功了才会有.地址为D:\coreclr2\coreclr\bin\obj\Windows_NT.x64.Debug\src\gc\sample,前缀路径大家替换成自己的路径就OK了. 首先我们还是从main函数来入手吧.首先是初始化GC. int __cdecl main(int argc, char* argv[]) { // // Initialize system info

CoreCLR源码探索(七) JIT的h5牛牛源码出售工作原理(入门篇)

很多C#的初学h5牛牛源码出售Q1446595067官网:h5.haozibbs.com者都会有这么一个疑问, .Net程序代码是如何被机器加载执行的? 最简单的解答是, C#会通过编译器(CodeDom, Roslyn)编译成IL代码, 然后CLR(.Net Framework, .Net Core, Mono)会把这些IL代码编译成目标机器的机器代码并执行. 相信大多数的C#的书籍都是这样一笔带过的. 这篇和下篇文章会深入讲解JIT的具体工作流程, 和前面的GC篇一样, 实现中的很多细节都是

【置顶】CoreCLR系列随笔

GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔:.NET CoreCLR之GC探索(3)(即将写的) CoreCLR探索系列 C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1) C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)

编译调试 .NET Core 5.0 Preview 并分析 Span 的实现原理

很久没有写过 .NET Core 相关的文章了,目前关店在家休息所以有些时间写一篇新的??.这次的文章主要介绍如何在 Linux 上编译调试最新的 .NET Core 5.0 Preview 与简单分析 Span 的实现原理.微软从 .NET Core 5.0 开始把 GIT 仓库 coreclr 与 corefx 合并移动到了 runtime 仓库,原有仓库仅用于维护 .NET Core 3.x,你可以从以下地址查看最新的源代码: https://github.com/dotnet/runti

【翻译】.NET 5 Preview2发布

在4月2日,发布了.NET 5.0 Preview2,这次发布对一些功能和性能做了相关的改进,同时后面也会实施5.0版本更多的功能,其中一些功能目前也dotnet/designs在.NET 5 Preview1中可以看到.NET 5里程碑中已经完成的建设任务,当然可以查看相关的设计资料进行反馈,同时可以下载Preview2并进行测试他. 可以在Windows MacOS和Linux下载.NET 5 Preview2 .NET 5 Preview2 And Runtimes Docker Imag

C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1)

一看这个标题,是不去取名有点绕呢?或者是,还有些问题?报告LZ...你的标题取得有问题,是个病句!(^ω^)!!!先不要急,其实我今天带给大家的就是CoreCLR中的coreclr.其中它是在名字叫HOST的一个子目录里面的.我的理解是HOST=宿主,GC因为是寄宿在WINDOWS中的,那么它是依靠什么寄宿呢,core-Console是我们狭义上的控制台吗?我觉得不是,我们可以把这个控制台理解为CoreCLR宿主的一个控制台,它控制了各个模块的调度,这全是我个人的理解. 这篇文章我也是采取随机抽

C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)

这篇文章是上篇的续集,本文将会继续介绍coreconsole.cpp里面的逻辑.也许大家会看一些CLR的书,我承认我没有看过,因为我觉得一个人,他再NB,那也是他自己的眼光,而且说句难听的,CLR也不是那个写书的人一个人完成的项目,所以他的眼光,我个人看来,也还是很有限的. 承接上篇文章的HostEnvironment,宿主环境:个人认为HOST是指的Windows内核.但是CLR有一个缺点,就是它并不是一个跨平台的,所以广义的说HOST应该是“操作系统内核”:下面我们来看看LoadCoreCL