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

CLR 深度探索系列:GC Heap 架構與實現機制(垃圾回收專題一)

     編輯:關於.NET

前言:托管堆的宏觀視角

在 CLR 托管進程啟動後,其記憶體空間包含:System Domain、Shared Domain、Default Domain,以及多種 Heap:Process Heap、JIT Code Heap、GC Heap 與 LOH (Large Object Heap)。本文聚焦 GC Heap 與 LOH 的架構設計與底層實現。

GC Heap 記憶體佈局全景

GC Heap 結構圖
GC Heap 結構示意:從低位址到高位址,包含多個 Heap Segment 與尾部 LOH

核心結構特徵

  • Heap Segment 串聯:一個 GC Heap 由一個或多個 Heap Segment 組成,雙向鏈表串聯。
  • 三代共存於 Segment:Gen 0、Gen 1、Gen 2 可分佈在同一 Segment,也可跨越多個 Segment。分代邊界動態調整。
  • Ephemeral Segment:最新配置的 Segment,包含 Gen 0/1(短暫代),配置指標在此推進。
  • LOH 緊隨 GC Heap 之後:大於 85,000 bytes 的物件直接配置於 LOH,不經分代機制。
  • 保留區域:Heap 尾部預留空間,用於安置 Pinned Object(被固定物件,如傳給非托管代碼的緩衝區),避免壓縮階段移動導致指針失效。

動態分代策略:GC 的「智慧」

CLR GC 團隊引入 「策略」機制:根據運行時行為動態調整分代大小。例如 Gen 0 預設 256 KB,若偵測到物件分配極頻繁,GC EE 會自動擴大 Gen 0,減少 GC 頻率,平衡吞吐量與延遲。

Windbg + SOS 實戰觀察 GC Heap

0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00ca1018
generation 1 starts at 0x00ca100c
generation 2 starts at 0x00ca1000
ephemeral segment allocation context: none
segment begin allocated size
00161e00 790d5588 790f4b38 0x0001f5b0 (128432)
00ca0000 00ca1000 00ca3ff4 0x00002ff4 (12276)
Large object heap starts at 0x01ca1000
segment begin allocated size
01ca0000 01ca1000 01ca3250 0x00002250 (8784)
Total Size 0x247f4 (149492)
GC Heap Size 0x247f4 (149492)

輸出揭示:單一 GC Heap、兩個 Segment(小物件堆)、緊接著的 LOH Segment、總大小約 146 KB。

核心類別實現:gc_heap 與 heap_segment

gc_heap — GC 堆管理核心類(節選關鍵成員)

class gc_heap {
public:
    // Heap Segment 管理
    heap_segment* make_heap_segment(BYTE* new_pages, size_t size);
    heap_segment* get_segment();
    void delete_heap_segment(heap_segment* seg);
    int grow_heap_segment(heap_segment* seg, size_t size);

    // LOH 管理(分離指標與非指標物件)
    l_heap* make_large_heap(BYTE* new_pages, size_t size, BOOL managed);
    l_heap* get_heap();
    void delete_large_heap(l_heap* hp);

    // 物件配置
    static CObjectHeader* allocate(size_t jsize, alloc_context* acontext);      // 小物件
    static CObjectHeader* allocate_large_object(size_t size, BOOL pointerp, alloc_context* acontext); // 大物件

    // GC 觸發與階段
    static int garbage_collect(int n); // 第 n 代回收
    void mark_phase(int condemned_gen_number, BOOL mark_only_p);
    void scavenge_pinned_object(BYTE* o); // 處理 pinned object

    // Card Table / Brick Table 操作
    size_t card_of(BYTE* object);
    void set_card(size_t card);
    void clear_cards(size_t start, size_t end);
    void copy_brick_card_table(BOOL heap_expand);

    // 關鍵資料成員
    BYTE* card_table;
    short* brick_table;
    BYTE* lowest_address;
    BYTE* highest_address;
    heap_segment* ephemeral_heap_segment;
    int condemned_generation_num;
    size_t segment_size;
    size_t lheap_size;
    l_heap* lheap;                    // LOH 管理結構
    size_t large_objects_size;        // LOH 門檻,預設 85000
    CFinalize* finalize_queue;        // 終結器佇列
    static int g_max_generation;      // 最大分代數(通常為 2)
    static size_t reserved_memory;    // 保留記憶體
};

heap_segment — 堆段結構

class heap_segment {
public:
    BYTE* allocated;      // 已配置末端
    BYTE* committed;      // 已提交末端
    BYTE* reserved;       // 保留區域末端
    BYTE* used;
    BYTE* mem;
    heap_segment* next;   // Segment 鏈表
    BYTE* plan_allocated;
    plug mPlug;           // 壓縮階段使用的 plug 結構
};

generation — 分代結構

class generation {
public:
    alloc_context allocation_context;
    heap_segment* allocation_segment;
    BYTE* free_list;
    heap_segment* start_segment;
    BYTE* allocation_start;
    size_t free_list_space;   // 剩餘可用空間
    size_t allocation_size;   // 已配置大小
};

LOH 設計哲學:為何不壓縮?

  • 移動大物件代價極高:記憶體拷貝、指針更新開銷巨大。
  • 採用 malloc-style allocator:基於開源實現,無壓縮機制。
  • 折中方案:分離指標/非指標物件:根據 MethodTable 掃描判斷物件是否包含指標,分別存放於 large_p_objects(含指標)與 large_np_objects(無指標)兩條鏈表。GC 掃描時可跳過無指標區塊,大幅減少追蹤開銷。

總結與展望

GC Heap 採用分段式、分代式、動態策略設計,配合 Card Table/Brick Table 輔助結構,實現高效記憶體管理。LOH 為大物件提供專屬區域,犧牲壓縮換取分配/回收效能。下一篇將深入剖析 Card Table 與 Brick Table 的具體實現與 GC 過程中的關鍵角色。

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