前言

由于业务需求,在探究.Net7的CLR,发现了一个不通的地方,也就是通过GCInfo获取到了对象之后。它并没有在GcScanRoots(对象扫描标记)里面对它进行标记,那么如果没有标记这个对象如何被计划阶段构建呢?仔细研读,发现它跟之前的代码之所以不同,是因为它把标记抽取出来,另外形成一个数组循环标记。本篇来看下。

概括

1.问题:

假如说有以下示例代码:

static void Main(string[] args)
{
Console.WriteLine("Tian Xia Feng Yun Chu Wo Bei!\r\n");
Program PM= new Program();
PM = null;
GC.Collect();
}

调用GC.Collect()函数,GC垃圾回收的第一步,就是标记。这个标记实质上可以分为以下几步。

一:获取到所有的线程(GetAllThreadList)

二:遍历循环这些线程的帧

三:通过遍历到的帧,找到这些帧对应的GCInfo

四:通过GCInfo的偏移量和寄存器找到相对应的对象

五:对找到的对象进行标记。

以上四步,基本上没变。第五步标记的时候,它加入了一些新的代码。

uint8_t *mark_queue_t::queue_mark(uint8_t *o)
{
Prefetch (o);
size_t slot_index = curr_slot_index; //这里有一个slot的索引
uint8_t* old_o = slot_table[slot_index];// 这里把这个索引的值从数组取出来
slot_table[slot_index] = o;//把新对象赋值到索引所在的数组内存
curr_slot_index = (slot_index + 1) % slot_count;
if (old_o == nullptr)//这个地方是关键,因为假如说你按照上面的示例代码,之前并没有这个PM对象。所以这个old_o是等于nullptr的,所以它直接return了。那么下面就不存在标记了。问题是这个标记不标记??还是在别的地方标记了??
return nullptr;
BOOL already_marked = marked (old_o);
if (already_marked)
{
return nullptr;
}
set_marked (old_o);
return old_o;
}

二:解决

要解决这个问题,就需要知道数组slot_table里面的数值是何时被变动的。这个其实很简单在VS里面可以,打个条件断点--值更改时中断。

结果发现在函数get_next_marked里面对slot_table数组里面的值(也就是对象)进行了一个标记

uint8_t* mark_queue_t::get_next_marked()
{
size_t slot_index = curr_slot_index; //获取到当前slot_table数组的总数索引
size_t empty_slot_count = 0;
while (empty_slot_count < slot_count) //从零开始循环总数索引
{
uint8_t* o = slot_table[slot_index]; //一个个的取出来,保存到o变量。
slot_table[slot_index] = nullptr; //然后把相应的索引位内存置0,以便下次标记的时候继续使用。
slot_index = (slot_index + 1) % slot_count;
if (o != nullptr) //如果这个o不等于null,那么下面的代码就是对它进行一个标记。
{
BOOL already_marked = marked (o); //判断它是否被标记
if (!already_marked) // 如果没有
{
set_marked (o); // 则对它进行标记
curr_slot_index = slot_index;
return o;//把标记过的对象返回
}
}
empty_slot_count++;//继续循环下一次,继续标记下一个
}
return nullptr;// 如果索引为空,则直接返回null
}

这个函数是被drain_mark_queue函数调用,而前者则是在GCScanRoot整个函数被完成之后调用的。

那么整体的就打通关节了,实质上它是抽取出来了,重新进行了标记。而非在GCScanRoot里面进行标记。

结尾:

作者:江湖评谈。公众号:jianghupt。扫码关注我,带你了解.Net高阶技术。

.Net7 GC标记阶段代码的改变的更多相关文章

  1. 《垃圾回收的算法与实现》——GC标记-压缩算法

    基本算法 Mark-Compact与Mark-Sweep的第一阶段均为标记活跃对象,第二阶段则不同,压缩算法则是将活跃对象逻辑上移到一起. Lisp2算法 对象头中增加forwarding指针,其用法 ...

  2. 《垃圾回收的算法与实现》——GC标记-清除算法

    基本算法 标记-清除算法由 ==标记阶段== 和 ==清除阶段== 构成. 标记即将所有活动的对象打上标记. 清除即将那些没有标记的对象进行回收. 标记与清除 遍历GC root引用,递归标记(设置对 ...

  3. Java GC 标记/清除算法

    1) 标记/清除算法是怎么来的? 我们在程序运行期间如果想进行垃圾回收,就必须让GC线程与程序当中的线程互相配合,才能在不影响程序运行的前提下,顺利的将垃圾进行回收. 为了达到这个目的,标记/清除算法 ...

  4. 1. GC标记-清除算法(Mark Sweep GC)

    世界上第一个GC算法,由 JohnMcCarthy 在1960年发布. 标记-清除算法由标记阶段和清除阶段构成. 标记阶段就是把所有的活动对象都做上标记的阶段. 标记阶段就是"遍历对象并标记 ...

  5. UIImage扩展用代码直接改变图片大小

    以下内容属于转载 在iOS中,uiimage没有用于修改大小的属性,要在代码中改变uiimage图片的大小,需要扩展UIImage类,如下: 头文件: #import<UIKit/UIKit.h ...

  6. legend3---18、第一阶段代码完成

    legend3---18.第一阶段代码完成 一.总结 一句话总结: 看起来麻烦或者自己因为厌烦不想做的,其实硬着头皮来做,一下子就做完了 1.layer_mobile的loading层和关闭loadi ...

  7. alpha阶段 代码结构及技术难点简介

    我们的产品是安卓端app,所以目前主要就是用Android Studio来进行代码开发. Android Studio的项目的结构还是比较清晰的,如下图,主要就是java文件夹内的代码部分(.java ...

  8. uboot两阶段代码分析

    1.启动过程特征总结(1)第一阶段为汇编阶段(start.s).第二阶段为C阶段(board.c中的start_armboot 函数)(2)第一阶段在SRAM中.第二阶段在DRAM中(3)第一阶段注重 ...

  9. PerfView专题 (第七篇):如何洞察触发 GC 的 C# 代码?

    一:背景 上一篇我们聊到了如何用 PerfView 洞察 GC 的变化,但总感觉还缺了点什么? 对,就是要跟踪到底是什么代码触发了 GC,这对我们分析由于 GC 导致的 CPU 爆高有非常大的参考价值 ...

  10. RxCache 的代码分析,含缓存时间duration的在代码中改变的自己实现的机制

    当应用进程创建 RxCache 的实例后,会给应用进程返回一个 rxcache实例及一个 ProxyProvider,代码如下: CacheProviders providers = new RxCa ...

随机推荐

  1. JS篇(004)-js 是一门怎样的语言,它有什么特点?

    答案: 1.脚本语言.JavaScript 是一种解释型的脚本语言,C.C++等语言先编译后执行,而 JavaScript 是在程序的运行过程中逐行进行解释. 2.基于对象.JavaScript 是一 ...

  2. tzoj:3613 突破包围

    http://www.tzcoder.cn/acmhome/problemdetail.do?&method=showdetail&id=3613 算出两两之间min距离,然后从起点开 ...

  3. NX二次开发,对象上色

    #include <uf_defs.h> #include <uf_ui_types.h> #include <uf.h> #include <uf_ui.h ...

  4. 高级纹理以及复杂而真实的应用——ShaderCp10

    --20.9.7 这章主要分成三个部分 立方体纹理(cubemap) 渲染纹理(RenderTexture,rt) 和程序纹理 一.立方体纹理 立方体纹理顾名思义是一种三维的纹理形状类似于立方体,由六 ...

  5. MySQL innodb存储引擎的数据存储结构

    InnoDB存储引擎的数据存储结构 B+ 树 为什么选择B+树? 因为B+树的叶子节点存储了所有的data,所以它的非叶子节点可以存储更多的key,使得树更矮:树的高度几乎就是I/O的次数,所以选择更 ...

  6. antd EditableProTable 组件的简单用法

    首先,antd EditableProTable 组件是在 table组件的基础上又封装了一层,可以实现行更新,删除,增加.只需动动手指,简单配置一下即可. 先下载 EditableProTable ...

  7. VSCode Snippet

    { // Place your snippets for javascript here. Each snippet is defined under a snippet name and has a ...

  8. 井字棋判断输赢C

    #include <stdio.h> int main(){ char a[3][3]; for (int i = 0; i < 3; ++i) { for (int j = 0; ...

  9. 12.8 linux学习第十五天

    今天老刘讲了第11章和第12章,感觉讲的速度很快,一气呵成,水都没怎么喝. 11.1 文件传输协议 一般来讲,人们将计算机联网的首要目的就是获取资料,而文件传输是一种非常重要的获取资料的方式.今天的互 ...

  10. 水印 canvas 实现

    let str = info; let c = document.createElement("canvas"); document.body.appendChild.c; let ...