C 語言標準未強制規定「棧/堆/靜態區」術語,但所有主流實現(GCC、MSVC、Clang、嵌入式編譯器)均採用此三區模型。理解它是寫出正確、高效 C 代碼的前提。
| 維度 | 棧 | 堆 | 靜態/全局區 |
|---|---|---|---|
| 分配方式 | 編譯器自動(函數調用/局部變量) | 程序員手動 malloc/free / new/delete | 編譯期/鏈接期確定 |
| 管理主體 | CPU/編譯器(棧指針 SP) | 程序員/分配器 | 加載器/運行時 |
| 生命周期 | 隨函數調用/返回自動銷毀 | 手動控制,可跨函數/模塊 | 程序啟動至結束 |
| 大小限制 | 較小(通常 1-8MB,可調) | 大(受限於虛擬地址空間) | 由可執行文件大小決定 |
| 分配速度 | 極快(移動指針) | 較慢(查找空閒塊、分裂/合併) | 零(編譯期完成) |
| 碎片問題 | 無(連續棧幀) | 有(外部/內部碎片) | 無 |
| 典型用途 | 局部變量、函數參數、返回地址、調用上下文 | 動態數組、鏈表/樹節點、大對象、生命周期不固定 | 全局變量、static 變量、字符串常量、只讀數據 |
| 錯誤風險 | 棧溢出(遞歸深/大局部數組) | 內存洩漏、雙重釋放、使用後釋放、越界 | 命名衝突、初始化順序問題 |
高地址 ──────────────────────────────────────
│ 內核空間 (3GB-4GB) │
├─────────────────────────────────────┤
│ 用戶空間棧 ↓ (向下增長) │ ← main() 局部變量、調用鏈
│ ... │
│ 空閒區域 │
│ ... │
│ 堆 ↑ (向上增長, malloc/mmap) │ ← 動態分配
├─────────────────────────────────────┤
│ BSS 段 (未初始化全局/static) │ ← 零初始化
│ Data 段 (已初始化全局/static) │ ← 讀寫數據
│ .rodata (只讀數據/字符串常量) │ ← 常量保護
│ Text 段 (代碼指令) │ ← 只讀執行
低地址 ──────────────────────────────────────
int global_init = 10; // Data 段
int global_uninit; // BSS 段 (隱式 0)
const int RO = 100; // .rodata (只讀)
char *str_literal = "hello"; // str_literal 在棧,"hello" 在 .rodata
void func() {
int local = 20; // 棧
static int s = 30; // Data/BSS 段 (僅初始化一次)
int *p = malloc(100); // p 在棧,指向堆 100 字節
free(p); // 必須釋放,否則洩漏
}
malloc/free,即操作堆。C99 甚至有 aligned_alloc。static int x 在靜態區,生命周期全程,僅作用域受限。char *p = "abc"; p[0]='x'; 未定義行為(段錯誤)。用 char p[] = "abc"; 才在棧可改。alloca/VLA 有風險。malloc,檢查返回值,配對 freeconst char*,防止誤改malloc 時:靜態池/棧/區域分配器替代-fstack-protector 防棧溢出