管中窥豹----.NET Core到.NET 8 托管堆的变迁
简介
https://www.cnblogs.com/lmy5215006/p/18494483
在研究.NET String底层结构时,我所观察到的情况与《.NET Core底层入门》,《.NET内存管理宝典》书中描述不符。故多研究了一下。发现.NET托管堆的结构也是越来越多,越来越高性能。
//示例代码
internal class Program
{
public const string constStr = "Lewis.liu";
static void Main(string[] args)
{
string name = "Lewis";
var person = Person.name;
var str = constStr;
Debugger.Break();
Console.ReadKey();
}
}
public class Person
{
public static string name = "liu";
}
.NET Core 3的托管堆结构
标准的SOH(0代,1代,2代),LOH结构,因此String Intern作为JIT编译阶段就能确定的静态内容,如果放在SOH堆中,就不太合适。存放在LOH堆中反而是更好的选择,因为LOH中没有升代,没有压缩,内存地址也不会移动。更加适合静态数据。
眼见为实----堆结构
眼见为实----是否分配在LOH
-
三个静态数据的内存地址
-
它们的GC 引用根
三个静态数据都引用了同一个gcroot -
GC根分配在LOH
.NET 5的托管堆结构
大家可以思考一个问题,LOH堆的定义是指>=85000byte的大对象才会进入的堆。而静态数据只是利用了LOH的特性,但本质与LOH描述不符,属于投机取巧的行为。也会给开发者带来困扰,比如说我。
因此在.NET 5 以后,CLR开发人员新增了一个Pinned object heap ,用于存储固定对象的特殊堆。来解决定义不匹配的问题
https://github.com/dotnet/runtime/blob/main/docs/design/features/PinnedHeap.md
https://devblogs.microsoft.com/dotnet/internals-of-the-poh
眼见为实----POH
眼见为实----是否分配在POH
.NET 8的托管堆结构
到了.NET 8 中,CLR团队又新增了NonGC heap ,顾名思义,这代表一个不会被GC的托管堆。很奇怪吧?
那有人就有疑问了? POH堆不是已经完美了吗?为什么还要新增堆?CLR团队给出了答案
主要是为了提高性能,没有写屏障,没有GC。这大大提高了效率
https://github.com/dotnet/runtime/blob/main/docs/design/features/NonGC-Heap.md
眼见为实----NonGC heap
眼见为实----是否分配在NonGC Heap
结论
CLR对静态数据存放一直都在优化,从最早的LOH到POH再到NonGC,在研究sting.Intern的过程中走了不少弯路。
因此大家在参考市面上的书籍时,切记知行合一,眼见为实。 否则用过时的知识去分享就贻笑大方啦