管中窺豹----.NET Core到.NET 8 託管堆的變遷

China Soft發表於2024-10-31

https://www.cnblogs.com/lmy5215006/p/18515971

在研究.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的託管堆結構

image
標準的SOH(0代,1代,2代),LOH結構,因此String Intern作為JIT編譯階段就能確定的靜態內容,如果放在SOH堆中,就不太合適。存放在LOH堆中反而是更好的選擇,因為LOH中沒有升代,沒有壓縮,記憶體地址也不會移動。更加適合靜態資料。

眼見為實----堆結構

image

眼見為實----是否分配在LOH

  1. 三個靜態資料的記憶體地址
    image

  2. 它們的GC 引用根
    image
    三個靜態資料都引用了同一個gcroot

  3. GC根分配在LOH
    image

.NET 5的託管堆結構

大家可以思考一個問題,LOH堆的定義是指>=85000byte的大物件才會進入的堆。而靜態資料只是利用了LOH的特性,但本質與LOH描述不符,屬於投機取巧的行為。也會給開發者帶來困擾,比如說我。
因此在.NET 5 以後,CLR開發人員新增了一個Pinned object heap ,用於儲存固定物件的特殊堆。來解決定義不匹配的問題
image

眼見為實----POH

image

眼見為實----是否分配在POH

image

.NET 8的託管堆結構

到了.NET 8 中,CLR團隊又新增了NonGC heap ,顧名思義,這代表一個不會被GC的託管堆。很奇怪吧?
那有人就有疑問了? POH堆不是已經完美了嗎?為什麼還要新增堆?CLR團隊給出了答案
image
主要是為了提高效能,沒有寫屏障,沒有GC。這大大提高了效率

https://github.com/dotnet/runtime/blob/main/docs/design/features/NonGC-Heap.md
image

眼見為實----NonGC heap

image

眼見為實----是否分配在NonGC Heap

image

結論

CLR對靜態資料存放一直都在最佳化,從最早的LOH到POH再到NonGC,在研究sting.Intern的過程中走了不少彎路。
因此大家在參考市面上的書籍時,切記知行合一,眼見為實。 否則用過時的知識去分享就貽笑大方啦

相關文章