首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

[你必須知道的.NET]第十九回:物件建立始末(下)

     編輯:關於.NET

本文介紹內容

  • 物件建立過程
  • 記憶體配置分析
  • 記憶體配置研究

接上回《第十八回:物件建立始末(上)》,繼續探討物件建立話題。

2.2 受控堆疊的記憶體配置機制

參考型別實例配置於受控堆疊,執行緒堆疊是物件生命週期起點。對 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 卸載。

基本概念交代

  • TypeHandle(型別控制代碼):指向對應實例的方法表,每個物件建立時包含此附加成員,佔 4 位元組。
  • SyncBlockIndex(同步區塊索引):用於執行緒同步,指向 Synchronization Block 記憶體區塊,佔 4 位元組。
  • NextObjPtr(下一個物件指標):受控堆疊維護的指標,標識下一個新建物件配置位置。CLR 初始化時位於受控堆疊基址。

引用型別配置過程說明

實作簡單型別說明:

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 指令完成物件建立,進而呼叫型別建構器完成初始化。具體過程:

  1. 宣告引用型別變數:VIPUser aUser; 僅是引用(指標),保存在執行緒堆疊,佔 4 Byte,自動初始化為 null。
  2. 執行 new 建立物件:aUser = new VIPUser(); 對應 newobj 指令,細分為:
    • CLR 依繼承層次搜尋,計算型別及所有父類別欄位總位元組數(本例 VIPUser 需 15 Byte,含父類別 User 的 id(4B)、user 參考(4B)、UserInfo 實例(6B)、自身 isVip(1B))。
    • 在當前 AppDomain 受控堆疊尋找未使用的連續空間(本例 20 位元組,含物件頭部),配置記憶體位址。GC 使用高效演算法:NextObjPtr 向前推進 20 位元組,清零間隔位元組,返回原 NextObjPtr 位址作為新物件位址。注意:堆疊配置向高位址擴展,堆疊向低位址擴展。
    • 實例欄位儲存有序:由上到下,父類別在前、子類別在後。
  3. 呼叫物件建構器完成初始化:
    • 建構 VIPUser 的 Type 物件(靜態欄位、方法表、實作介面等),配置於 Loader Heap。
    • 初始化 TypeHandle 指向 Loader Heap 上的 MethodTable;SyncBlockIndex 指向同步區塊。
    • 呼叫 VIPUser 建構器,先遞歸向上執行父類別初始化至 System.Object,再返回執行子類別初始化。最終 newobj 配置的位址傳給 this 參數,引用傳給堆疊上宣告的 aUser。

記憶體配置圖示

受控堆疊中連續配置的物件在記憶體中連續,配置機制極高效。

2.3 必要補充

  • 值類型中的引用型別欄位、引用型別中的值類型欄位配置情況:值類型巢狀引用型別時,引用保存在堆疊,實際物件在 GC 堆疊;引用型別巢狀值類型時,值類型欄位作為實例一部分保存在 GC 堆疊。值類型總是配置在宣告它的地方。
  • 方法調用過程:MethodTable 包含型別元資料,類別載入時在 Loader Heap 建立。物件實例的 TypeHandle 指向 MethodTable 偏移處(預設偏移 12 Byte)。呼叫方法時,CLR 依 TypeHandle 找到 MethodTable,定位具體方法,JIT 編譯 IL 為本地 CPU 指令,保存在動態記憶體執行,並快取供下次使用。MethodTable 中的 Method Slot Table 為線性鏈表,按繼承虛方法、引入虛方法、實例方法、靜態方法排序。子類別覆寫父類別虛方法時會覆蓋。
  • 靜態欄位記憶體配置與釋放:靜態欄位保存在方法表中,生命週期從建立到 AppDomain 卸載。無論建立多少物件,靜態欄位在記憶體中只有一份。僅由靜態建構函數初始化,確保在任何物件建立前或靜態成員被引用前執行。

3. 結論

物件建立過程是接觸 CLR 運行機制的入口,也是認識 .NET 自動記憶體管理的關鍵。本文詳細論述物件建立、記憶體配置、初始化過程與方法呼叫,建立相對全面理解,清楚掌握執行緒堆疊與受控堆疊執行機制。物件總有生有滅,本文簡述其「生」,偉大的開始。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved