動態記憶體管理雖強大,但未正確釋放導致的洩漏最難偵錯。輕微洩漏或許不易察覺,嚴重者導致效能下降、記憶體耗盡、甚至拖垮其他程式。Visual Studio 提供強大的 CRT Debug Heap 機制,能精準定位洩漏位置與分配堆疊。本文完整說明啟用、解讀、斷點、比較四大核心技巧。
#define _CRTDBG_MAP_ALLOC
#include
#include
// 順序不可變:_CRTDBG_MAP_ALLOC → stdlib.h → crtdbg.h
作用:將 malloc/free 映射到 _malloc_dbg/_free_dbg,記錄檔案名與行號。僅在 Debug 版本 (_DEBUG 定義) 生效。
// 程式結束前呼叫
_CrtDumpMemoryLeaks();
或在程式啟動早期設定自動輸出:
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
兩個旗標必須同時設定,程式在任何出口退出都會自動報告。
// 強制輸出到 VS Output 視窗 Debug 頁
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
Detected memory leaks!
Dumping objects ->
C:\Project\Test\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
Data: 41 42
Object dump complete.
{45}:記憶體配置序號(第 45 次配置),可用於設定斷點。normal block:區塊類型(normal/client/CRT)。at 0x00441BA0:記憶體位址。2 bytes long:大小。Data: 41 42:前 16 位元組內容 (ASCII 'A','B')。memleak.cpp(15):來源檔案與行號(需定義 _CRTDBG_MAP_ALLOC)。雙擊可直接跳轉。| 類型 | 說明 |
|---|---|
| normal block | 程式碼自行配置的記憶體 (malloc/new) |
| client block | MFC 物件需呼叫解構函式時使用 (DEBUG_NEW) |
| CRT block | CRT 內部自用,通常不會洩漏 |
| free block | 已釋放區塊,不出現在洩漏報告 |
| ignore block | 開發者標記忽略的區塊 |
洩漏報告顯示配置序號 {45},表示第 45 次配置洩漏。但同一行程式碼可能執行多次,需找出具體哪一次未釋放。
_crtBreakAlloc(若用 MSVCRTD.dll 則輸入 {,,msvcrtd.dll}_crtBreakAlloc)。45。// 程式啟動早期
_crtBreakAlloc = 45;
// 或
_CrtSetBreakAlloc(45);
_CrtMemState s1, s2, s3;
_CrtMemCheckpoint(&s1); // 快照 1:關鍵程式碼前
// 執行疑似洩漏的程式碼區段
DoSomething();
_CrtMemCheckpoint(&s2); // 快照 2:關鍵程式碼後
if (_CrtMemDifference(&s3, &s1, &s2)) {
_CrtMemDumpStatistics(&s3); // 輸出差異統計
}
輸出範例:
0 bytes in 0 Free Blocks.
75 bytes in 3 Normal Blocks.
5037 bytes in 41 CRT Blocks.
Largest number used: 5308 bytes.
Total allocations: 7559 bytes.
若 Normal Blocks 數量/大小增加,表示該區段有洩漏。可用二分法縮小範圍定位具體行號。
CRT 偵錯堆積是 VC++ 開發者偵測記憶體洩漏的利器。掌握啟用映射、自動報告、配置序號斷點、快照比較四大技巧,就能從茫茫程式碼中精準挖出洩漏根源。善用 MSDN 文件深入研究,你也能成為偵錯高手。