.Net CLR GC plan_phase二叉树和Brick_table

楔子

Plan_Phase(GC的计划阶段)很早就接触了,但是后面一直没用到,忘记了,此次又用到了,几乎忘光了,费了很大力气理解它,记录下,以免又忘记了。

主题

计划阶段(plan_phase)主要就两个部分,一个是堆里面的对象构建一颗庞大的二叉树。但是,这个二叉树如果过于庞大,则成了性能瓶颈。于是乎,第二个部分Brick_table出现了,它主要是分割这个庞大的二叉树,以消弭性能瓶颈问题。

构建不规则二叉树

构建二叉树之前,先了解一些概念。当实例化一个对象之后,这个对象存储在堆里面。堆实际上是一长串的内存地址,不受CPU栈的管控,所以导致了它不能自动释放,需要手动。在这一长串的地址里面,可以分为固定对象和非固定对象。

1.固定对象概念

首先看下固定句柄,固定句柄就是把托管对象传递到费托管对象的堆栈里面去,固定句柄本身在托管里面进行管理,而它包含的对象就叫做固定对象。

至于非固定对象,就是普通的对象了,此处不再赘述。

在进行GC计划阶段的时候,会循环遍历当前需要收集的垃圾的代(generation)里面包含的所有堆,然后区分出包含固定对象的堆段,和非固定对象的堆段。

区分规则是怎么样的呢?非常简单,具体的就是如果相邻的两个对象都是非固定对象或者都是固定对象,则把这两个对象作为一个堆段,继续查找后面的对象。如果后续的对象跟前面的对象相同,则跟前面的两个对象放在一起形成一个堆段(如果后面还有相同的,则继续放在一起),如果不同,则此堆段到此为止。后面继续以同样的逻辑遍历,形成一个个的小堆段(以node表述)。

2.这里有一个特性:

固定堆段(也就是固定对象组成的堆段)的末尾必须跟一个非固定对象(这么做的原因,是避免固定对象的末尾被覆盖,只覆盖非固定对象的末尾)。

二叉树的构建,就建立在这些固定对象堆段和非固定对象堆段上的。这些一个个的堆段作为二叉树的根节点和叶子结点,构成了二叉树的本身。

3.相关构建

一:plug_and_pair结构
plug_and_pair存在于上面被分割的堆段的前面,堆段以node(节点)表示,则此结构(plug_and_pair*)node)[-1]的位置

struct plug
{uint8_t *  skew[plug_skew / sizeof(uint8_t *)];
};class pair
{public:short left;short right;
};
struct plug_and_pair
{pair        m_pair;plug        m_plug;
};

pair的left和right成员分别表示当前堆段距离其前一个堆段和后一个堆段的距离长度。

二:构建逻辑
构建逻辑分为三种,数字一般可以分为奇数和偶数。计算机也是一样,但是除了这两种之外,偶数里面还可以分裂出另外一种情况,就是一个数字是2的次方数。举个例子,比如:1,2,3,4,5,6,7,8,9,10。这十个数字里面,明显的奇数:1,3,5,7,9。偶数:2,4,6,8,10。再分裂下二的次方数:2,4,8。注意看,最后分裂的结果2,4,8分别是2的1次方,2次方和3次方。剔除了6和10这两个数字。
那么总结下,三种逻辑以上面试个数字举例分别为:
遍历循环以上十个数字。
第一种(if(true)):1,2,4,8 if(!(n&(n-1))) n分别为2,4,8。if里为true
第二种(if(true)):3,5,7,9 if(n&1) n分别为1,3,5,7,9。if里为true
第三种(if(true)):6,10 如果以上两种不成立,则到第三种这里来。

三:构建树身
如上所述,通过对堆里面的对象进行固定和非固定对象区分,变成一个个的小堆段(node)。这些小堆段从左至右依次编号:1,2,3,4,5,6,7,8,9.......N。然后通过构建逻辑这部分进入到if里面去。

1.(if(true)):

1,2,4,8编号的node会进入这里,主要是设置左节点和tree
set_node_left_child (new_node, (tree - new_node));tree = new_node;

2.(if(true)):

3,5,7,9编号的node会进入这里,主要是设置右节点
set_node_right_child (last_node, (new_node - last_node));

3.(if(true)):

6,10编号的会进入这里,主要是把原来的二叉树的右子节点变成新的node(new_node)的左子节点,切断二叉树与它自己右子节点的联系。然后把新的node(new_node),变成原来二叉树的右子节点。uint8_t*  earlier_node = tree;size_t imax = logcount(sequence_number) - 2;//这里是获取需要变成的二叉树的右子树节点的层级。for (size_t i = 0; i != imax; i++)//如果层级不等于0,则获取到二叉树根节点到右子节点的距离,然后把根节点与右子节点相加得到二叉树右子节点。如此循环遍历,到二叉树最底层的右子节点为止。{earlier_node = earlier_node + node_right_child (earlier_node);}获取到最后一颗二叉树的根节点的右子树的距离int tmp_offset = node_right_child (earlier_node);assert (tmp_offset); // should never be empty把最后一颗二叉树的根节点和最后一颗二叉树的右子节点相加,设置为新的node(new_node)的左子树。set_node_left_child (new_node, ((earlier_node + tmp_offset ) - new_node));把最后一颗二叉树的右子树节点设置为新的node(new_node)节点,同时也是断了开与原来右子树的联系。set_node_right_child (earlier_node, (new_node - earlier_node));

GC plan_phase的二叉树构建本身并不复杂,而是复杂的逻辑和诡异的思维方式。

最终的构建的二叉树形式如下图所示:
0f584535c85e81ed0f8a17109cf00aac.png

四.分割二叉树
当以上二叉树被构建之后,如有几千个节点(node,小堆段)会形成庞大的一棵树。所以需要分割功能,用以来保证性能。

当二叉树包含的小堆段(node)的长度超过2的12次方(4kb),这棵二叉树就会被分割。

4bdafb816378b9c58c4f097af2e6eca0.png

Brick_table里面属于这个4节点范围内的都是赋值为-1,表示你要在4节点上寻找你需要的节点。

源码:

最后上一下源码
1.构建二叉树:

uint8_t* gc_heap::insert_node (uint8_t* new_node, size_t sequence_number,uint8_t* tree, uint8_t* last_node)
{dprintf (3, ("IN: %Ix(%Ix), T: %Ix(%Ix), L: %Ix(%Ix) [%Ix]",(size_t)new_node, brick_of(new_node),(size_t)tree, brick_of(tree),(size_t)last_node, brick_of(last_node),sequence_number));if (power_of_two_p (sequence_number)){set_node_left_child (new_node, (tree - new_node));dprintf (3, ("NT: %Ix, LC->%Ix", (size_t)new_node, (tree - new_node)));tree = new_node;}else{if (oddp (sequence_number)){set_node_right_child (last_node, (new_node - last_node));dprintf (3, ("%Ix RC->%Ix", last_node, (new_node - last_node)));}else{uint8_t*  earlier_node = tree;size_t imax = logcount(sequence_number) - 2;for (size_t i = 0; i != imax; i++){earlier_node = earlier_node + node_right_child (earlier_node);}int tmp_offset = node_right_child (earlier_node);assert (tmp_offset); // should never be emptyset_node_left_child (new_node, ((earlier_node + tmp_offset ) - new_node));set_node_right_child (earlier_node, (new_node - earlier_node));dprintf (3, ("%Ix LC->%Ix, %Ix RC->%Ix",new_node, ((earlier_node + tmp_offset ) - new_node),earlier_node, (new_node - earlier_node)));}}return tree;
}

2.切割二叉树:

size_t gc_heap::update_brick_table (uint8_t* tree, size_t current_brick,uint8_t* x, uint8_t* plug_end)
{dprintf (3, ("tree: %Ix, current b: %Ix, x: %Ix, plug_end: %Ix",tree, current_brick, x, plug_end));if (tree != NULL){dprintf (3, ("b- %Ix->%Ix pointing to tree %Ix",current_brick, (size_t)(tree - brick_address (current_brick)), tree));set_brick (current_brick, (tree - brick_address (current_brick)));//brick_table索引处的值是:根节点tree距离当前current_brick对应的地址的距离}else{dprintf (3, ("b- %Ix->-1", current_brick));set_brick (current_brick, -1);}size_t  b = 1 + current_brick;ptrdiff_t  offset = 0;size_t last_br = brick_of (plug_end-1);//上一个plug节点的末尾current_brick = brick_of (x-1);//当前的plug_startdprintf (3, ("ubt: %Ix->%Ix]->%Ix]", b, last_br, current_brick));while (b <= current_brick){if (b <= last_br){set_brick (b, --offset);}else{set_brick (b,-1);}b++;}return brick_of (x);
}

以上参考:
https://github.com/dotnet/coreclr/blob/main/src/gc/gc.cpp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vijos p1484 ISBN号码

描述每一本正式出版的图书都有一个ISBN号码与之对应&#xff0c;ISBN码包括9位数字、1位识别码和3位分隔符&#xff0c;其规定格式如“x-xxx-xxxxx-x”&#xff0c;其中符号“-”就是分隔符&#xff08;键盘上的减号&#xff09;&#xff0c;最后一位是识别码&#xff0c;例如0…

scrapy爬虫启示录-小伙子老夫看你血气方刚这本《爬虫秘录》就传给你了

文章来源&#xff1a; IT源点 第一章 误入歧途 每个学习爬虫的人都有一颗爱美的心&#xff0c;俺也是一样的。那么多的美眉图片&#xff0c;不薅下来&#xff0c;没了谁负责。于是夜里孤枕难眠的老男孩开始了他的撸码之旅。从此在学习爬虫&#xff0c;学习Python的道路上越走…

自己设置假期的日历控件_在假期旅行时使用PC娱乐自己

自己设置假期的日历控件Staying connected may be hard no matter what network you are on, and in flight Wi-Fi isn’t pervasive enough to count on. Here are tips and tricks to keep yourself entertained when unplugged and traveling. 无论您使用什么网络&#xff0…

.Net CLR异常和windows C++ 异常调用栈简析

楔子前面一篇研究了下C异常的&#xff0c;这篇来看下&#xff0c;CLR的异常内存模型&#xff0c;实际上都是一个模型&#xff0c;承继自windows异常处理机制。不同的是&#xff0c;有VC编译器(vcruntime.dll&#xff09;接管的部分&#xff0c;被CLR里面的函数ProcessCLRExcept…

Codeforces936C. Lock Puzzle

给个串&#xff0c;只能用操作shift x表示把后面x个字符翻转后放到串的前面。问s串怎么操作能变t串。n<2000&#xff0c;操作次数<6100。 打VP时这转来转去的有点晕。。。 可以想一种逐步构造的方法&#xff0c;即从一个小的完成构造的部分通过一顿操作&#xff0c;在不影…

公共服务领域英文译写规范_公共领域日:对版权和公共领域重要性的思考

公共服务领域英文译写规范The first of the year is Public Domain Day, a day intended to call attention to copyright issues and the public domain. At the Center for the Study of the Public Domain they have an interesting (and sobering) review of works that wo…

Elasticsearch 实战经验总结

Centos7下es 7.7.0安装配置 怎么安装使用elasticsearch-head插件 用logstash同步Mysql数据到ES Springboot使用ES官方推荐方式REST Client整合ES实现关键词高亮 ELK-Elasticsearch&#xff0c;Logstash&#xff0c;kibana搭建基于日志文件的日志分析系统 设置elasticsearc…

.Net 7 的 AOT 和 CLR有什么区别?

楔子&#xff1a;AOT和 CLR的区别是什么呢&#xff1f;大部分人肯定会说&#xff0c;一个编译成本地机器码&#xff08;Native Code&#xff09;&#xff0c;一个是JIT即时编译的结果。这么说&#xff0c;其实也对&#xff0c;但是不具体。具体应该怎么看呢&#xff1f;AOTAOT实…

接入amazon avs_每日新闻综述:亚马逊将互联网接入推向全球的宏伟计划

接入amazon avsPlus Snap’s big push to stay relevant, Amazon’s Alexa-powered AirPods alternatives, more Android Q news, and a lot more. It’s time to talk about the biggest, coolest, or generally most interesting stories from the last 24 hours. 加上Snap保…

计算的未来

我自己倒是后来也是觉得我自己可以想象一个未来的技术&#xff0c;就是以后的编程的语言和库可以抽象现在的一些高级语言的关键字。比如要写一个编辑器的时候&#xff0c;只要给点这些东西的数据结构和数据流向&#xff0c;而一些什么很繁琐的一些底层编码都是可以用高级语言来…

nginx 实用配置问题总结

配置 tomcat&#xff0c;nginx&#xff0c;解决 post 请求超时问题nginx 跨域问题 CORS policy: No Access-Control-Allow-Originnginx 配置静态验证文件&#xff0c;报 404&#xff0c;解决方案nginx 获取用户真实 IPcentos 部署 php 网站方法-使用 nginx ssl https

零部件分类属性

离散制造业的研发、生产跟产品零部件紧密联系在一起&#xff0c;从企业业务流程来说零部件涉及研发、采购、仓储、生产、质量、售后和配件等多个部门&#xff0c;为了更好地管理零部件&#xff0c;下面我们一起来看看零部件概念及分类。1、按行业属性分类&#xff08;1&#xf…

键盘忍者:使用单个热键弹出Vista日历

We’ve covered how to access the Windows Vista Calendar using the keyboard, but what if you wanted to assign a single keystroke to pop up the calendar? Yeah, sure, you can just click it with the mouse, but where’s the geek fun in that? 我们已经介绍了如何…

Linux下全局安装composer方法

# 下载composer [vagrantlocalhost ~]$ curl -sS https://getcomposer.org/installer | php# 将composer.phar文件移动到bin目录以便全局使用composer命令 [vagrantlocalhost ~]$ mv composer.phar /usr/local/bin/composer# 切换国内源 [vagrantlocalhost ~]$ composer config…

如何使用必应地图 WPF 控件

如何使用必应地图 WPF 控件如何使用必应地图 WPF 控件作者&#xff1a;WPFDevelopersOrg - 驚鏵原文链接&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用.NET40&#xff1b;Visual Studio 2019;Bing Maps WPF 控件需要 .NET Framework 4.0和 Windows S…

如何保存推特链接以供以后从台式机和手机阅读

Have you come across a lot of interesting links from Twitter, but you don’t have the time to read all of them? Today we’ll show you how to read these links later from your desktop and phone. 您是否遇到过Twitter上很多有趣的链接&#xff0c;但没有时间阅读所…

scrapy爬虫实战分享

自动登录脚本参考scrapy爬虫启示录-小伙子老夫看你血气方刚这本《爬虫秘录》就传给你了Scrapy初章-Scrapy理论简介Scrapy次章-啥也不干就是爬图Scrapy第四章-设置代理IP偷偷爬图Scrapy第三章-图片存库MysqlScrapy第五章-多线程加速爬图Scrapy终章-1024福利Scrapy最最最终章-搂一…

【重大更新】DevExpress v17.2新版亮点—Bootstrap篇(二)

用户界面套包DevExpress v17.2日前终于正式发布&#xff0c;本站将以连载的形式为大家介绍各版本新增内容。本文将介绍了Bootstrap Controls v17.2 的CardView、Charts、Editors、GridView、Layout等新功能&#xff0c;快来下载试用新版本&#xff01; GridView Toolbar 在此版…

盘点 .NET 7 新功能

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;20分钟)本文翻译于 Jeremy Likness, Angelos Petropoulos 和 Jon Douglas 的博客.NET 7 为C# 11/F# 7、.NET MAUI、ASP.NET Core/Blazor、Web API、WinForms、WPF 等应用程序带来了更高的性能和新功能。使用 .NET 7&a…

onlyoffice采坑笔记

中文版onlyoffice/documentserver镜像制作onlyoffice 20并发限制处理&#xff0c;up to 20 maximumonlyoffice安装-Linuxwindows 10 下用docker安装onlyoffice服务 onlyoffice安装-Linux 0 点赞 ⋅ 0 回复 ⋅ 3月前onlyoffice相关命令记录 0 点赞 ⋅ 0 回复 ⋅ 3月前onlyoffice…