管中窥豹—-.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的托管堆结构

管中窥豹----.NET Core到.NET 8 托管堆的变迁
标准的SOH(0代,1代,2代),LOH结构,因此String Intern作为JIT编译阶段就能确定的静态内容,如果放在SOH堆中,就不太合适。存放在LOH堆中反而是更好的选择,因为LOH中没有升代,没有压缩,内存地址也不会移动。更加适合静态数据。

眼见为实----堆结构

管中窥豹----.NET Core到.NET 8 托管堆的变迁

眼见为实----是否分配在LOH

  1. 三个静态数据的内存地址
    管中窥豹----.NET Core到.NET 8 托管堆的变迁

  2. 它们的GC 引用根
    管中窥豹----.NET Core到.NET 8 托管堆的变迁
    三个静态数据都引用了同一个gcroot

  3. GC根分配在LOH
    管中窥豹----.NET Core到.NET 8 托管堆的变迁

.NET 5的托管堆结构

大家可以思考一个问题,LOH堆的定义是指>=85000byte的大对象才会进入的堆。而静态数据只是利用了LOH的特性,但本质与LOH描述不符,属于投机取巧的行为。也会给开发者带来困扰,比如说我。
因此在.NET 5 以后,CLR开发人员新增了一个Pinned object heap ,用于存储固定对象的特殊堆。来解决定义不匹配的问题
管中窥豹----.NET Core到.NET 8 托管堆的变迁

https://github.com/dotnet/runtime/blob/main/docs/design/features/PinnedHeap.md
https://devblogs.microsoft.com/dotnet/internals-of-the-poh

眼见为实----POH

管中窥豹----.NET Core到.NET 8 托管堆的变迁

眼见为实----是否分配在POH

管中窥豹----.NET Core到.NET 8 托管堆的变迁

.NET 8的托管堆结构

到了.NET 8 中,CLR团队又新增了NonGC heap ,顾名思义,这代表一个不会被GC的托管堆。很奇怪吧?
那有人就有疑问了? POH堆不是已经完美了吗?为什么还要新增堆?CLR团队给出了答案
管中窥豹----.NET Core到.NET 8 托管堆的变迁
主要是为了提高性能,没有写屏障,没有GC。这大大提高了效率

https://github.com/dotnet/runtime/blob/main/docs/design/features/NonGC-Heap.md
管中窥豹----.NET Core到.NET 8 托管堆的变迁

眼见为实----NonGC heap

管中窥豹----.NET Core到.NET 8 托管堆的变迁

眼见为实----是否分配在NonGC Heap

管中窥豹----.NET Core到.NET 8 托管堆的变迁

结论

CLR对静态数据存放一直都在优化,从最早的LOH到POH再到NonGC,在研究sting.Intern的过程中走了不少弯路。
因此大家在参考市面上的书籍时,切记知行合一,眼见为实。 否则用过时的知识去分享就贻笑大方啦

发表评论

相关文章