基本概念
CLR:公共語言運行時,類似Java的jvm,是直接建立在OS上的虛擬環境,主要任務是管理代碼運行。CLR現在支持幾十種現代的編程語言爲它編寫代碼,然後以一種中間語言(Intermediate Langeoage,IL)代碼的形成被執行。
.Net CLR非常詳細講解了clr原理東西。
線程堆棧:用於分配值類型實例。堆棧主要由操作系統管理,而不受垃圾收集器的控制,當值類型實例所在方法結束時,其存儲單位自動釋放。執行效率高,但存儲容量有限。
GC堆:用於分配小對象實例。如果引用類型對象的實例大小小於85000字節,實例將被分配在GC堆上,當有內存分配或者回收時,垃圾收集器可能會對GC堆進行壓縮。
LOH堆:用於分配大對象實例。如果引用類型對象的實例大小不小於85000字節時,該實例將被分配到LOH堆上,而LOH堆不會被壓縮,而且只在完全GC回收時被回收。
TypeHandle(類型句柄):指向對應實例的方法表,每個對象創建時都包含該附加成員,並且佔用4個字節的內存空間。我們知道,每個類型都對應於一個方法表,方法表創建於編譯時,主要包含了類型的特徵信息、實現的接口數目、方法表的slot數目等。
NextObjPtr:由託管堆維護的一個指針,用於標識下一個新建對象分配時在託管堆中所處的位置。CLR初始化時,NextObjPtr位於託管堆的基地址
分配原則
.Net中的資源分爲託管資源(受clr管理)和非託管資源(不受clr管理),取決於變量的數據類型,託管資源被存放在託管堆和堆棧中。
託管資源數據類型分爲值類型和引用類型,關於兩者的聯繫,之前的博客 【傻傻分不清楚】C#值類型、引用類型
做了比較。
值類型實例
對於值類型的實例,CLR在運行時有兩種分配方式:(1) 如果該值類型的實例作爲類型中的方法(Method)中的局部變量,則該實例被創建在線程棧上;(2) 如果該值類型的實例作爲類型的成員,則該實例作爲引用類型(引用類型在GC堆或者LOH上創建)的實例的一部分,被創建在GC堆上
public class Test1
{
private int i;
//上面(2)中的情況,生成Test的實例的同時,int類型的實例i被創建在GC堆上
public Test1()
{
byte b =0;
//(1)中的情況,byte類型的實例b被創建在執行這段代碼的線程棧上
}
}
引用類型實例
對於引用類型的實例,CLR在運行時也有兩種分配方式:(1) 如果該引用類型的實例的Size<85000Byte,則該實例被創建在GC(Garbage Collection)堆上(當CLR在分配和回收對象時,GC可能會對GC堆進行壓縮);(2) 如果該引用類型的實例的Size>=85000byte,則該實例被創建在LOH(Large
Object Heap)上(LOH不會被壓縮)。
public class Test2
{
private int[] intArr;
public Test2()
{
private Object o = new Object();
//引用o存在線程棧上,它指向GC堆上的Object實例
intArr = new int[21250];
//符合(2)中的Size條件,int數組的實例被創建在LOH上
}
}
有大神寫的博客,.NET下的內存分配機制做了非常詳細的分析!