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

C/C++ 程式記憶體佈局完整解析:堆疊、堆、資料段與程式碼段

     編輯:關於C語言

前言

理解程式在記憶體中的分佈,是寫出高效、無 Bug 代碼的基石。本文系統梳理五大記憶體區域、堆疊與堆的深度對比、存取效率實測,並以經典範例程式標註每個變數的所屬區域。

一、五大記憶體區域

區域內容管理方式生命週期
程式碼段函式機器碼、常數字面值系統/連結器程式執行期間
資料段(已初始化)全域/靜態已初始化變數系統程式執行期間
BSS 段(未初始化)全域/靜態未初始化變數(歸零)系統程式執行期間
堆疊區域變數、函式參數、返回位址、暫存器保存編譯器自動函式呼叫期間
堆動態配置記憶體程式設計師手動配置到釋放/程式結束

二、經典範例標註

int a = 0;           // 資料段(已初始化)
char *p1;            // BSS 段(未初始化全域指標)

int main() {
    int b;                 // 堆疊
    char s[] = "abc";      // 堆疊(陣列內容複製自常數區)
    char *p2;              // 堆疊(指標變數本身)
    char *p3 = "123456";   // p3 在堆疊,"123456\0" 在常數區
    static int c = 0;      // 資料段(已初始化靜態)

    p1 = malloc(10);       // 10 bytes 在堆
    p2 = malloc(20);       // 20 bytes 在堆
    strcpy(p1, "123456");  // "123456\0" 在常數區,編譯器可能合併與 p3 指向同一地址
}

三、堆疊 vs 堆 深度對比

維度堆疊堆
配置方式編譯器自動(如區域變數)程式設計師手動 malloc/new
釋放方式自動(離開作用域)手動 free/delete,否則洩漏
位址增長向低位址(x86)向高位址
記憶體連續性連續不連續(鏈表管理空閒塊)
大小限制Windows 預設 1-2 MB,編譯期固定受限於虛擬記憶體,可達 GB 級
配置速度極快(指標遞減)較慢(遍歷空閒鏈表、分割合併)
碎片問題無易產生外部碎片
存取效率高(區域性好、指針解引用少)稍低(多一次指針間接)

四、存取效率實證

char s1[] = "aaaaaaaaaa";  // 堆疊陣列
char *s2 = "bbbbbbbbbb";   // 常數區字串,s2 指標在堆疊

// 存取 s1[1]:直接 [ebp - offset] → cl
// 存取 s2[1]:先讀指標到 edx,再 [edx + 1] → al
// 反組譯顯示堆疊陣列少一條指令,較快

五、函式呼叫堆疊幀結構

  1. 返回位址(呼叫點下一指令)
  2. 參數(右至左壓入,呼叫慣例相關)
  3. 區域變數
  4. 舊 EBP(幀指標鏈)

返回時逆序彈出:區域變數 → 參數 → 返回位址 → 續行。

六、堆區塊結構

  • 區塊頭部通常記錄大小(供 free/delete 使用)
  • 配置時從空閒鏈表尋找首個滿足大小的塊(First-Fit)
  • 剩餘空間重新掛入空閒鏈表

七、VirtualAlloc 進階選項

Windows 提供 VirtualAlloc 直接在進程位址空間保留/認交記憶體,繞過堆管理器,適用於大塊、對齊、需精確控制的場景,但使用複雜度高。

八、資料結構視角的「堆」與「堆疊」

  • 資料結構堆疊:LIFO,push/pop
  • 資料結構堆:優先佇列實作,滿足堆性質
  • 兩者與記憶體管理區域同名但概念完全不同,僅因歷史慣例並稱

九、經典比喻

堆疊像去餐廳吃飯:點菜(配置)→ 吃(使用)→ 走人(自動清理),快但自由度低。
堆像自己做菜:買食材(malloc)→ 處理(初始化)→ 吃(使用)→ 洗碗(free),麻煩但靈活、份量大。

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