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 bcl\system\gc.cs
// if you change this!
//上面那句ENGLISH的意思就是如果要改这里面的值,必须先改变bc1\system\gc.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++随笔:.NET CoreCLR之GC探索(2)的更多相关文章
- C++随笔:.NET CoreCLR之GC探索(4)
今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...
- C++随笔:.NET CoreCLR之GC探索(3)
有几天没写GC相关的文章了哈,今天我讲GC的方式是通过一个小的Sample来讲解,这个小的示例代码只有全部Build成功了才会有.地址为D:\coreclr2\coreclr\bin\obj\Wind ...
- C++随笔:.NET CoreCLR之GC探索(1)
一直是.NET程序员,但是.NET的核心其实还是C++,所以我准备花 一点时间来研究CoreCLR和CoreFX.希望这个系列的文章能给大家带来 帮助. GC的代码有很多很多,而且结构层次对于一个初学 ...
- CoreCLR源码探索(五) GC内存收集器的内部实现 调试篇
在上一篇中我分析了CoreCLR中GC的内部处理, 在这一篇我将使用LLDB实际跟踪CoreCLR中GC,关于如何使用LLDB调试CoreCLR的介绍可以看: 微软官方的文档,地址 我在第3篇中的介绍 ...
- CoreCLR文档翻译 - GC的设计
此文档来源于CoreCLR的BOTR(The Book of the Runtime), 点击打开原文 一切著作权归微软公司所有 GC的设计 作者: Maoni Stephens (@maoni0) ...
- CoreCLR源码探索(三) GC内存分配器的内部实现
在前一篇中我讲解了new是怎么工作的, 但是却一笔跳过了内存分配相关的部分. 在这一篇中我将详细讲解GC内存分配器的内部实现. 在看这一篇之前请必须先看完微软BOTR文档中的"Garbage ...
- CoreCLR源码探索(四) GC内存收集器的内部实现 分析篇
在这篇中我将讲述GC Collector内部的实现, 这是CoreCLR中除了JIT以外最复杂部分,下面一些概念目前尚未有公开的文档和书籍讲到. 为了分析这部分我花了一个多月的时间,期间也多次向Cor ...
- CoreCLR源码探索(一) Object是什么
.Net程序员们每天都在和Object在打交道 如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" 这个答案是对的 ...
- CoreCLR源码探索(二) new是什么
前一篇我们看到了CoreCLR中对Object的定义,这一篇我们将会看CoreCLR中对new的定义和处理 new对于.Net程序员们来说同样是耳熟能详的关键词,我们每天都会用到new,然而new究竟 ...
随机推荐
- 关于这段时间学习 EntityFramework的 一点感悟
Ado.Net,用了N多年,Entity Framework也关注了很多年. 每当项目转型的时候,就花费大巴的时间,学习一番,潮流的东西. 这个Orm很多,这个EF很火,这么多年了,我还是不敢用,虽然 ...
- 使用Visual Studio SDK制作GLSL词法着色插件
使用Visual Studio SDK制作GLSL词法着色插件 我们在Visual Studio上开发OpenGL ES项目时,避免不了写Shader.这时在vs里直接编辑shader就会显得很方便. ...
- html5标签canvas函数drawImage使用方法
html5中标签canvas,函数drawImage(): 使用drawImage()方法绘制图像.绘图环境提供了该方法的三个不同版本.参数传递三种形式: drawImage(image,x,y):在 ...
- Node.js:path、url、querystring模块
Path模块 该模块提供了对文件或目录路径处理的方法,使用require('path')引用. 1.获取文件路径最后部分basename 使用basename(path[,ext])方法来获取路径的最 ...
- HTML5轻松实现搜索框提示文字点击消失---及placeholder颜色的设置
在做搜索框的时候无意间发现html5的input里有个placeholder属性能轻松实现提示文字点击消失功能,之前还傻傻的在用js来实现类似功能... 示例 <form action=&quo ...
- WPF 普通属性变化通知
问题描述:使用ObservableCollection<OrderItem> source 给Datagrid.ItemsSource赋值,在后台更新source集合后,前台Datagri ...
- js闭包for循环总是只执行最后一个值得解决方法
<style> li{ list-style: none;width:40px;height: 40px;text-align:center;line-height: 40px;curso ...
- javascript排序
利用array中的sort()排序 w3cfunction sortNumber(a,b) { return a - b } var arr = new Array(6) arr[0] = " ...
- 【JS基础】循环
for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块)的条件 语句 3 在循环(代码块)已被 ...
- IP报头
位字段的值设置为二进制的0100表示IP版本4(IPv4).设置为0110表示IP版本6(IPv6) 位,它表示32位字长的IP报头长度,设计报头长度的原因是数据包可选字段大小会发生变化.IP ...