程式執行時,記憶體分配策略直接決定效能、穩定性與安全性。C++ 將可程式化記憶體劃分為三大區域:**靜態儲存區**、**堆疊**與**堆**。理解它們的生命週期、分配方式與常見陷阱,是寫出健壯程式的前提。
static 變數(全域/區域/類靜態成員)、字串常值、const 全域常數。push/sub rsp)完成。new/malloc 顯式請求。delete/free 釋放前一直存在。
char* p = "Hello World1"; // p 在堆疊,"Hello World1" 在靜態區(唯讀)
char a[] = "Hello World2"; // a 在堆疊,內容複製到堆疊(可寫)
p[2] = 'A'; // 執行期崩潰:嘗試寫入唯讀記憶體
a[2] = 'A'; // 正常:修改堆疊副本
補充:相同字串常值可能合併儲存(編譯器最佳化),p 與 p1 指向同一地址。
char* f1() {
char a = 'x';
return &a; // 錯誤:a 隨函數結束銷毀,回傳懸空位址
}
char* f2() {
char* p = new char[4]; // 正確:堆記憶體存活,呼叫端負責 delete[]
return p;
}
呼叫 f1() 後寫入回傳指標屬**未定義行為**(UB),除錯模式常偵測到,釋出模式可能沉默破壞資料。
delete
void leak() {
char* p = new char[100];
// 無 delete[] p,函數結束 p 消失,100 bytes 永不可及
}
長期運行的服務程式若洩漏,最終耗盡記憶體導致 OOM Killer 終止進程。**鐵律:每個 new 對應 delete,每個 new[] 對應 delete[]。** 現代 C++ 推薦智慧指標(unique_ptr, shared_ptr)實現 RAII 自動管理。
| 維度 | 靜態區 | 堆疊 | 堆 |
|---|---|---|---|
| 分配者 | 編譯器/連結器 | 編譯器指令 | 程式設計師 (new/malloc) |
| 釋放者 | 程式結束由 OS 回收 | 編譯器指令 (自動) | 程式設計師 (delete/free) |
| 生命週期 | 程式全期 | 函數作用域 | 手動控制 |
| 空間大小 | 固定 (執行檔體積) | 小 (MB 級) | 大 (GB/TB 級) |
| 分配速度 | 無 (啟動前) | 極快 (指令級) | 較慢 (系統呼叫/鎖) |
| 典型用途 | 全域狀態、常值 | 區域變數、遞歸 | 動態資料、大物件、跨作用域共享 |
| 風險 | 命名衝突、初始化順序 | 溢位、大物件 | 洩漏、懸空指標、碎片 |
std::vector、std::string 內部自動管理堆記憶體,介面乾淨。std::make_unique<T>()、std::make_shared<T>(),零洩漏風險。T* 或 T&,擁有者用智慧指標。std::vector 或 std::unique_ptr<T[]>,勿手動 new[]。記憶體管理是 C++ 核心競爭力所在。掌握三大區域特性、生命週期與所有權模型,配合現代 RAII 慣用語,即能寫出高效且安全的系統級程式碼。