首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

C++ 記憶體洩漏偵測完整指南:MFC/非 MFC 環境下的 CRT 偵測、定點監控與輸出重導向

     編輯:關於VC++

前言:兩大環境的偵測機制差異

  • MFC 環境:自動於程式結束時在 Output 視窗報告洩漏,亦可用 `CMemoryState` 定點檢查
  • 非 MFC (純 CRT):需手動呼叫 CRT 偵測函式,本文重點說明此部分

一、基本洩漏報告:_CrtDumpMemoryLeaks

#include 

// 程式結束前呼叫
_CrtDumpMemoryLeaks();

自動化:在程式進入點 (main/WinMain) 最開頭加入:

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

CRT 將在每個 `exit` 路徑自動呼叫 `_CrtDumpMemoryLeaks`。

二、定點監控:_CrtMemState 差異比對

適用於「某區塊代碼前後」的洩漏偵測:

_CrtMemState s1, s2, s3;

_CrtMemCheckpoint(&s1); // 記錄初始狀態

// --- 待測試代碼區塊 ---
int* p = new int[100];
delete[] p; // 故意漏掉 delete 會被偵測
// ----------------------

_CrtMemCheckpoint(&s2); // 記錄結束狀態

if (_CrtMemDifference(&s3, &s1, &s2)) { // 比較差異存入 s3
    _CrtMemDumpAllObjectsSince(&s3); // 輸出 s3 以來所有未釋放物件
}

三、輸出重導向:_CrtSetReportMode / _CrtSetReportFile

預設輸出至 Debug Output 視窗,可導向檔案或訊息盒:

1. 導向檔案

// 需 ATL 或手動 CreateFile
CAtlFile file;
file.Create(_T("D:\\leak_report.txt"), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS);

_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, file.m_h); // ATL CAtlFile 隱含轉換

// 或純 Win32
HANDLE hFile = CreateFile(_T("D:\\leak_report.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, hFile);

2. 導向訊息盒 (類 Assert 視窗)

_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_WNDW); // 彈出 終止/重試/忽略 視窗

3. 導向自訂回呼函式 (攔截/過濾/記錄)

int MyReportHook(int reportType, char* msg, int* retval) {
    *retval = 0;
    if (reportType == _CRT_WARN) {
        // 自訂處理:寫 Log、發送網路、GUI 顯示等
        OutputDebugStringA("[LEAK] ");
        OutputDebugStringA(msg);
        OutputDebugStringA("\n");
    }
    return TRUE; // TRUE=不再傳遞給預設處理器
}

// 安裝
_CrtSetReportHook(MyReportHook);

四、MFC 環境專用:CMemoryState

CMemoryState ms1, ms2, ms3;
ms1.Checkpoint();
// ... 測試代碼 ...
ms2.Checkpoint();
if (ms3.Difference(ms1, ms2))
    ms3.DumpAllObjectsSince(); // 輸出至 afxDump (Debug Output)

五、進階技巧與最佳實踐

  1. 偵測新增/刪除不配對:搭配 `DEBUG_NEW` (MFC) 或自訂 `operator new/delete` (參考文章 9169)
  2. 洩漏定位到行號:`_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF)` 啟用每次配置檢查 (極慢,僅小範圍用)
  3. 忽略已知誤報:`_CrtSetBreakAlloc(allocNum)` 在特定配置序號中斷,配合輸出的 `{123}` 序號
  4. Release 版不偵測:所有 CRT 偵測功能僅在 Debug CRT (`/MDd` `/MTd`) 生效
  5. 跨 DLL 邊界洩漏:各模組獨立 CRT 堆,需在各 DLL 內部偵測,或統一使用共享 CRT (`/MD`)

六、常見輸出解讀

Detected memory leaks!
D:\Project\Test.cpp(15) : {123} normal block at 0x004A3B20, 40 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
```
  • `{123}`:配置序號,可用 `_CrtSetBreakAlloc(123)` 中斷
  • `normal block`:一般 `new/malloc` 配置
  • `client block`:MFC `DEBUG_NEW` 配置 (含檔案/行號)
  • `Data`:前 16 位元組內容 (十六進位),`CD` 為 Debug 填充模式

七、整合到專案的標準啟動碼

// stdafx.cpp 或 main.cpp 最開頭
#ifdef _DEBUG
#include 
// 自動報告 + 檔案輸出
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// 可選:_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, hLogFile);
#endif
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved