malloc 是 C 語言動態記憶體分配的核心函數,理解其底層的 空閒鏈表 機制,能幫你寫出更高效、更少碎片的程式,也能在面試中脫穎而出。本文從原型、用法切入,深入剖析分配/釋放流程、碎片整理策略與常見坑點。
void *malloc(size_t size); // 分配 size 位元組,成功返回指標,失敗返回 NULL
void free(void *ptr); // 釋放 ptr 指向的記憶體塊
頭檔:<stdlib.h> (C) / <cstdlib> (C++)。C++ 建議優先使用 new/delete 或智慧指標。
堆內部維護一個 雙向循環鏈表,每個節點記錄:size、is_free、prev/next 指標。初始只有一個大塊「荒野區塊」。
size ≥ 請求大小 + 元資料 的空閒塊。is_free = false,返回使用者可用地址(跳過元資料頭)。is_free = true。長期運行後,空閒鏈表會產生大量細小碎片(外部碎片)。當請求大塊記憶體失敗時,分配器會觸發:
sbrk/mmap 擴展堆邊界。| 錯誤類型 | 後果 | 防範 |
|---|---|---|
| 未檢查 NULL 直接使用 | 段錯誤 | 永遠檢查回傳值 |
| 釋放後繼續使用 | Use-after-free,未定義行為 | free 後置 nullptr |
| 重複 free | 堆損壞 | 同上 |
| 越界寫入 | 破壞元資料/相鄰塊 | 使用 AddressSanitizer、valgrind |
| 忘記 free | 記憶體洩漏 | RAII、智慧指標、靜態分析 |
malloc/free:庫函數,不呼叫建構/解構函數,僅操作原始位元組。new/delete:運算子,自動呼叫建構/解構函數,型別安全,可重載。new/delete,否則物件未初始化/未清理。掌握 malloc 的空閒鏈表模型,不只是知其然,更能在設計自定義分配器、排查堆損壞、優化高頻分配場景時,擁有底層視角的直覺判斷力。