管中窥豹----.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

  1. 三个静态数据的内存地址

  2. 它们的GC 引用根

    三个静态数据都引用了同一个gcroot

  3. GC根分配在LOH

.NET 5的托管堆结构

大家可以思考一个问题,LOH堆的定义是指>=85000byte的大对象才会进入的堆。而静态数据只是利用了LOH的特性,但本质与LOH描述不符,属于投机取巧的行为。也会给开发者带来困扰,比如说我。

因此在.NET 5 以后,CLR开发人员新增了一个Pinned object heap ,用于存储固定对象的特殊堆。来解决定义不匹配的问题

眼见为实----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的过程中走了不少弯路。

因此大家在参考市面上的书籍时,切记知行合一,眼见为实。 否则用过时的知识去分享就贻笑大方啦