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的託管堆結構
標準的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 ,用於儲存固定物件的特殊堆。來解決定義不匹配的問題
眼見為實----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的過程中走了不少彎路。
因此大家在參考市面上的書籍時,切記知行合一,眼見為實。 否則用過時的知識去分享就貽笑大方啦