.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,一经查实,立即删除!

相关文章

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…

接入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保…

键盘忍者:使用单个热键弹出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? 我们已经介绍了如何…

如何使用必应地图 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;但没有时间阅读所…

【重大更新】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…

nb-iot链路层加密_Google为低端Android手机和IoT设备创建了更快的加密

nb-iot链路层加密Google谷歌Low-resource Android phones and IoT devices don’t have the processing power to use modern encryption services, which makes them vulnerable to hacking. That’s why Google is introducing Adiantum, a super-fast encryption standard f…

MediatRPC - 基于MediatR和Quic通讯实现的RPC框架,比GRPC更简洁更低耦合,开源发布第一版...

大家好&#xff0c;我是失业在家&#xff0c;正在找工作的博主Jerry。作为一个.Net架构师&#xff0c;就要研究编程艺术&#xff0c;例如SOLID原则和各种设计模式。根据这些原则和实践&#xff0c;实现了一个更简洁更低耦合的RPC&#xff08;Remote Procedure Calls&#xff09…

wii拆机_设置防砖保护以保护和增强Wii

wii拆机We’ve shown you how to hack your Wii for homebrew software, emulators, and DVD playback, now it’s time to safeguard your Wii against bricking and fix some annoyances—like that stupid “Press A” health screen. 我们已经向您展示了如何破解Wii的自制软…

龙芯IPC追平Zen2 稳步推进产业生态

日前&#xff0c;2022年信息技术自主创新高峰论坛在南京成功召开&#xff0c;来自政府、产业、各行业领域的领导、专家学者、企业代表齐聚长江之滨&#xff0c;共话信息产业自主创新发展。铁流谈谈会上几个亮点。龙芯LA664追平AMD zen2相对于一些技术引进CPU在引进海外技术后CP…

摄像头水平视野垂直视野?_如何在“动物穿越:新视野”中的梦中游览某人的岛屿...

摄像头水平视野垂直视野?The promised second summer update for Animal Crossing: New Horizons has been released, and it restores the ability to visit another player’s island in your dreams. Before you can do so, though, you’ll need a Nintendo Online member…

中文版onlyoffice镜像制作

原文同步于&#xff1a;https://www.daxueyiwu.com/post/761 拉取5.4.2.46版本onlyoffice/documentserver镜像 docker pull onlyoffice/documentserver:5.4.2.46 该版本是支持20个连接数破解限制的最后一个版本&#xff0c;也是对中文字体界面显示中文不乱码支持比较好的一个版…

使用访问控制策略访问服务网格内的服务

当在实施服务网格时&#xff0c;不可避免的存在网格外服务访问网格内服务的情况&#xff0c;也就是服务网格的平滑落地。这种中间状态可能会持续较长的时间&#xff0c;也是我们在落地的时候需要解决的问题之一。又或者&#xff0c;有的应用处于某些考虑并不适合使用服务网格&a…

gfi截图_GFI Backup Home Edition是Windows的免费数据备份实用程序

gfi截图In today’s tough economic times the last thing you want is to lose important data because you couldn’t afford a quality backup utility. Today we look at GFI Backup Home Edition, a completely free professional grade backup solution. 在当今艰难的经…

使用BeetleX.MQTT构建服务

已经有很长一段时间没有写代码&#xff0c;为了不让自己的代码技能有所下降所以针对BeetleX扩展了一个MQTT协议来保持自己的代码设计和编写能力。接下来简单介绍一下如何使用BeetleX.MQTT来构建对应的TCP或WebSocket服务。 以下实现是针对MQTT 3.1.1版本&#xff0c;协议的实…