進程虛擬位址空間佈局 (典型 Linux x86-64)
高位址
+------------------------+
| 栈 - 向下增長 | 局部變數、函式參數、返回位址、暫存器保存、alloca
| ... |
| ↓ |
| |
| ↑ |
| ... |
| 堆 - 向上增長 | malloc/free/new/delete、動態分配、brk/mmap
+------------------------+
| BSS 段 | 未初始化全域/靜態變數、零初始化、編譯器分配大小、不佔檔案空間
+------------------------+
| 數據段 | 已初始化全域/靜態變數 (非零)、const 全域 (視架構)、編譯時確定大小、佔檔案空間
+------------------------+
| 只讀數據段 | 字串字面值、const 全域 (部分架構)、vtable、只讀表
+------------------------+
| 代碼段 | 機器指令、函式體、常數池、只讀、可共享
+------------------------+
低位址
各段詳細特性
| 段 | 存放內容 | 生命週期 | 權限 | 典型大小 | 分配方式 |
|---|
| 代碼段 | 函式機器碼、字串字面值、只讀常數 | 程式運行全程 | R-X (可讀可執行) | 固定 | 連結器分配 |
| 只讀數據 | const 全域、vtable、跳轉表 | 程式運行全程 | R-- | 固定 | 連結器分配 |
| 數據段 | 已初始化全域/靜態變數 (int g=10;) | 程式運行全程 | RW- | 固定 | 連結器分配,載入時從映像檔複製 |
| BSS段 | 未初始化全域/靜態變數 (int g; static int s;) | 程式運行全程 | RW- | 固定 | 載入器清零,不佔映像檔空間 |
| 堆 | 動態分配記憶體 (malloc/free/new/delete) | 手動管理 | RW- | 動態增長 | 分配器管理 (brk/mmap) |
| 棧 | 局部變數、參數、返回位址、暫存器溢出、VLA、alloca | 函式呼叫期間 | RW- (通常設不可執行 NX) | 動態增長 (預設 8MiB Linux, 1MiB Windows) | 編譯器生成序言/尾聲自動管理 |
常見錯誤與排查
- 棧溢位: 遞迴過深、大型 VLA/局部陣列、alloca 過大 → `Segmentation fault`。改用堆分配或增大棧 (`ulimit -s`, `/F` 編譯選項)。
- 堆破壞: 緩衝區溢出、雙重釋放、使用已釋放記憶體、釋放非堆指標 → 行為未定義。使用 AddressSanitizer (`-fsanitize=address`)、Valgrind 檢測。
- 全域變數初始化順序: 不同編譯單元全域變數初始化順序未定義 → 依賴順序的邏輯錯誤。使用「構造時首次使用」模式 (函式靜態局部變數) 解決。
- 字串字面值修改: `char *p = "hello"; p[0] = 'H';` → 崩潰 (寫入只讀段)。改用 `char p[] = "hello";` 或 `char *p = strdup("hello");`。