接上回《第十八回:物件建立始末(上)》,繼續探討物件建立話題。
參考型別實例配置於受控堆疊,執行緒堆疊是物件生命週期起點。對 32 位處理器,應用程式完成程序初始化後,CLR 在程序可用位址空間配置一塊保留區域——即受控堆疊(Managed Heap),不對應實體記憶體。
受控堆疊依存儲資訊不同劃分:最重要的是垃圾回收堆疊(GC Heap)與載入堆疊(Loader Heap)。GC Heap 存儲物件實例,受 GC 管理;Loader Heap 分為 High-Frequency Heap、Low-Frequency Heap、Stub Heap,存儲元資料資訊(Type 物件、Method Table 等)。Loader Heap 不受 GC 控制,生命週期從建立到 AppDomain 卸載。
實作簡單型別說明:
public class UserInfo { private Int32 age = -1; private char level = 'A'; }
public class User { private Int32 id; private UserInfo user; }
public class VIPUser : User {
public bool isVip;
public bool IsVipUser() { return isVip; }
public static void Main() {
VIPUser aUser = new VIPUser();
aUser.isVip = true;
Console.WriteLine(aUser.IsVipUser());
}
}
反編譯 IL 可知:new 關鍵字編譯為 newobj 指令完成物件建立,進而呼叫型別建構器完成初始化。具體過程:
VIPUser aUser; 僅是引用(指標),保存在執行緒堆疊,佔 4 Byte,自動初始化為 null。aUser = new VIPUser(); 對應 newobj 指令,細分為:
NextObjPtr 向前推進 20 位元組,清零間隔位元組,返回原 NextObjPtr 位址作為新物件位址。注意:堆疊配置向高位址擴展,堆疊向低位址擴展。TypeHandle 指向 Loader Heap 上的 MethodTable;SyncBlockIndex 指向同步區塊。System.Object,再返回執行子類別初始化。最終 newobj 配置的位址傳給 this 參數,引用傳給堆疊上宣告的 aUser。
受控堆疊中連續配置的物件在記憶體中連續,配置機制極高效。
TypeHandle 指向 MethodTable 偏移處(預設偏移 12 Byte)。呼叫方法時,CLR 依 TypeHandle 找到 MethodTable,定位具體方法,JIT 編譯 IL 為本地 CPU 指令,保存在動態記憶體執行,並快取供下次使用。MethodTable 中的 Method Slot Table 為線性鏈表,按繼承虛方法、引入虛方法、實例方法、靜態方法排序。子類別覆寫父類別虛方法時會覆蓋。物件建立過程是接觸 CLR 運行機制的入口,也是認識 .NET 自動記憶體管理的關鍵。本文詳細論述物件建立、記憶體配置、初始化過程與方法呼叫,建立相對全面理解,清楚掌握執行緒堆疊與受控堆疊執行機制。物件總有生有滅,本文簡述其「生」,偉大的開始。