C++ 程序內存佈局五大區域
| 區域 | 別名 | 管理方式 | 典型內容 | 生命週期 |
| 棧 | Stack | 編譯器自動管理 | 局部變量、函數參數、返回地址、寄存器保存 | 隨作用域自動釋放 |
| 堆 | Heap | 程序員手動管理 (new/delete) | 動態分配對象 | 手動釋放,程序結束由 OS 回收 |
| 自由存儲區 | Free Store | 程序員手動管理 (malloc/free) | C 風格動態內存 | 手動釋放,程序結束由 OS 回收 |
| 全局/靜態存儲區 | Data/BSS Segment | 編譯器/鏈接器管理 | 全局變量、靜態變量 (static) | 程序啟動到結束 |
| 常量存儲區 | Literal Pool / .rodata | 只讀,編譯器管理 | 字符串字面值、const 修飾的全局/靜態變量 | 程序啟動到結束 |
詳細說明
1. 棧
- 位於用戶虛擬地址空間高地址,向低地址增長
- 函數調用時壓棧:返回地址、參數、局部變量、保存的寄存器
- 函數返回時彈棧,自動銷毀局部對象(調用析構函數)
- 大小有限(Linux 默認 8MB),棧溢出導致程序崩潰
2. 堆
- C++ 特有術語,對應
new/delete、new[]/delete[]
- 向高地址增長,非連續區域,由分配器管理空閒塊鏈表
- 程序員負責配對釋放,忘記
delete 導致記憶體洩漏
- 可動態擴展,受限於虛擬地址空間大小
3. 自由存儲區
- C 語言術語,對應
malloc/free/realloc
- 與堆在物理上通常是同一區域,但管理 API 不同
- 嚴禁混用:
new 必須配 delete,malloc 必須配 free
- C++ 中
new 會調用構造函數,malloc 不會
4. 全局/靜態存儲區
- 分為 .data 段(已初始化)和 .bss 段(未初始化,自動清零)
- C++ 取消了 C 語言區分初始化/未初始化的區別,統一管理
static 修飾局部變量:存儲在這裡,但作用域限於函數內
- 程序啟動時分配,結束時統一釋放
5. 常量存儲區
- 存放字符串字面值(
"hello")、const 全局/靜態變量
- 通常位於只讀內存頁(
.rodata 段),寫入會觸發段錯誤
- 字符串字面值可能被編譯器合併(相同字符串共用地址)
代碼驗證範例
#include
using namespace std;
int global = 10; // .data 段
static int s_global = 20; // .data 段(內部鏈接)
const int c_global = 30; // .rodata 段
void func() {
int local = 1; // 棧
static int s_local = 2; // .data 段
const int c_local = 3; // 棧(非靜態 const 不進常量區)
int* p1 = new int(4); // 堆
int* p2 = (int*)malloc(sizeof(int)); // 自由存儲區
*p2 = 5;
cout << "local: " << &local << endl; // 高地址
cout << "s_local: " << &s_local << endl; // 低地址
cout << "p1 (heap): " << p1 << endl; // 中間地址
cout << "p2 (free): " << p2 << endl; // 中間地址
cout << "global: " << &global << endl; // 低地址
cout << "literal: " << "hello" << endl; // 只讀區
delete p1; free(p2);
}
工程最佳實踐
- 優先使用棧/智能指針:
std::vector, std::unique_ptr, std::shared_ptr 自動管理生命週期
- 避免裸指針 new/delete:易洩漏、易雙重釋放、異常不安全
- 大對象放堆:避免棧溢出
- 常量正確性:盡量用
const、constexpr,利用編譯器優化與只讀保護