首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows XP 使用者模式記憶體空間探勘(二):執行緒堆疊深度解析

     編輯:VC 教學

前言

承接上篇整體掃描,本文聚焦「堆疊」——每個執行緒擁有的獨立記憶體區域。我們將實測主執行緒與工作者執行緒的堆疊佈局,驗證 NT_TIB(Thread Information Block)中 StackBase/StackLimit 的真實含義,並揭示 PAGE_GUARD 在堆疊動態增長中的關鍵角色。

一、主執行緒堆疊實測

1.1 斷點觀察 ESP

VS2008 除錯中斷,主執行緒 ESP = 0x00124914,落在區塊 0x00120000 ~ 0x00130000(大小 64KB,MEM_COMMIT,PAGE_READWRITE)。

1.2 NT_TIB 結構驗證

// FS:[0] 指向 NT_TIB
NT_TIB *pTib = (NT_TIB*)__readfsdword(0);
pTib->StackBase  // 0x00130000
pTib->StackLimit // 0x0000A000  (注意:這不是實際可用下限!)

StackBase 與區塊上緣 0x00130000 吻合,但 StackLimit 只有 0xA000,顯然不代表實際保護邊界。

1.3 完整堆疊區塊圖

BaseAddressAllocationBaseRegionSizeStateProtectType
0x000300000x000300000x00100000MEM_RESERVEPAGE_NOACCESSMEM_PRIVATE
0x001200000x000300000x00010000MEM_COMMITPAGE_READWRITE | PAGE_GUARDMEM_PRIVATE
0x001300000x000300000x00010000MEM_COMMITPAGE_READWRITEMEM_PRIVATE

關鍵發現:

  • 系統一次保留 1MB(0x00030000 ~ 0x00130000),AllocationBase 統一為 0x00030000。
  • 初始僅提交頂端 64KB(0x00130000 - 0x00120000),中間插入一頁 PAGE_GUARD(0x00120000 ~ 0x00121000)。
  • StackLimit (0xA000) 僅反映初始提交下限,非硬性邊界。

二、PAGE_GUARD 機制:堆疊自動增長的秘密

MSDN 定義:PAGE_GUARD 頁被存取時,系統引發 STATUS_GUARD_PAGE_VIOLATION 例外,隨後移除 PAGE_GUARD 屬性,將該頁轉為正常 PAGE_READWRITE,並將下一頁標記為新的 PAGE_GUARD。

流程:

  1. ESP 向下增長,觸及 Guard Page(如 0x00120000)。
  2. CPU 觸發例外,核心捕獲,檢查是否屬於堆疊擴展範圍(AllocationBase 以內)。
  3. 是 → 提交該頁,移除 Guard,下一頁設 Guard,執行緒繼續。
  4. 否 → 真正的堆疊溢位,終止進程。

這機制實現了「按需提交」,節省實體記憶體,同時保留 1MB 虛擬空間上限。

三、工作者執行緒堆疊識別

掃描所有 MEM_PRIVATE + PAGE_GUARD 區塊,即可定位所有執行緒堆疊:

BaseAddressRegionSizeAllocationBase推測執行緒
0x001200000x10000x00030000主執行緒
0x02A400000x10000x02A30000工作者執行緒 1
0x03B500000x10000x03B40000工作者執行緒 2
0x04C600000x10000x04C50000工作者執行緒 3

每個執行緒堆疊保留 1MB(預設 CreateThread dwStackSize=0),Guard Page 位於已提交區域的下緣。

四、堆疊大小配置與最佳實踐

  • CreateThread 第 2 參數 dwStackSize:0 = 預設 1MB 保留;>0 指定保留大小(系統向上對齊至頁邊界)。
  • 連結器選項 /STACK:reserve[,commit]:設定主執行緒堆疊保留/初始提交大小。
  • 避免在堆疊分配大型陣列/結構(>几 KB),改用堆積(new/malloc)或靜態儲存。
  • 遞迴深度不可控時,考慮增加保留大小或改寫為迭代。
  • x64 程式預設堆疊 1MB 保留,但 64 位元指標佔用雙倍空間,深度遞迴更易溢位。

五、總結

堆疊不是固定大小的塊,而是「保留大、提交小、Guard Page 推進」的動態結構。NT_TIB.StackBase 指向保留區頂端,StackLimit 僅反映當前提交下限。理解此機制,有助於診斷堆疊溢位、優化執行緒記憶體佔用、編寫高可靠的多執行緒程式。

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