1 MFC內存
一個內存泄漏信息指出每一個內存泄漏塊的類型爲普通、客戶端或者CRT型。在實際程序中,普通型和客戶端型式最多見的類型。小程序
普通型內存塊(Normal Blocks)是你的程序日常分配的內存類型。函數
客戶端型內存塊( Client Blocks)是MFC程序給須要析構的對象分配的內存塊。MFC的new操做能夠選擇普通型或客戶端型中合適的一種做爲將要被建立的對象的內存塊類型。.net
CRT內存塊(CRT Blocks)是CRT庫爲本身使用而分配的內存塊。CRT在處理本身的釋放內存操做時使用這些塊,因此在內存泄漏報告中這種類型並不常見,除非發生嚴重異常(例如:CRT庫出錯)。orm
自由塊(Free Blocks),它是已經被釋放的內存塊;對象
忽略塊(Ignore Blocks.),它是已經被特殊標示的內存塊。blog
2 檢測方法
2.1 1、直接定位法
2.1.1 輸出內存泄漏信息
一、在stdafx.h頭文件中添加兩行代碼內存
#define _CRTDBG_MAP_ALLO
#include <crtdbg.h>io
二、添加函數
_CrtDumpMemoryLeaks();//程序只有一個退出點時,在程序退出的地方添加
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); //程序有多個退出點時,在程序開始的地方添加class
2.1.2 定位
若是在輸出窗口直接顯示了內存泄漏的位置和行數,直接雙擊文件顯示的那行,自動跳到內存泄漏的位置。test
Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18}
normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
2.2 2、二分法查找內存泄漏,比較內存狀態
使用_CrtMemCheckpoint捕捉內存快照,使用_CrtMemState 結構存儲內存快照,在可能出現內存泄漏的程序段的開始和結尾分別捕捉內存快照,snapshot1和snapshot2,使用_CrtMemDifference比較snapshot1與snapshot2內存狀態的差別,分析出內存泄漏,依次縮小程序代碼範圍鎖定內存泄漏位置。你可使用_CrtMemDumpStatistics輸出_CrtMemState 內存結構中內容。
使用示例
_CrtMemState sOld, sNew, sDif;
_CrtMemCheckpoint(&sOld);
int *pIndex = new int[10];
_CrtMemCheckpoint(&sNew);
if(_CrtMemDifference(&sDif,&sOld,&sNew))
_CrtMemDumpStatistics(&sDif);
輸出(Output)窗口
0 bytes in 0 Free Blocks.
40 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 40 bytes.
Total allocations: 40 bytes.
2.3 3、指定申請內存的序號
使用 _CrtSetBreakAlloc()或者直接給_crtBreakAlloc賦值爲內存申請的序號N,啓動程序後,程序在內存申請到序號N時自動中斷,咱們就能夠【調用堆棧】窗口來判斷是那塊內存申請出錯。
使用示例
//程序開始或該分配內存序號以前,如第18次申請的內存塊 _CrtSetBreakAlloc(18);// _crtBreakAlloc = 18; 3 檢測代碼整理 // Debug.h: interface for the CDebug class. //--------------------------------------------------------------------------------- // 內存泄露信息示例 : // {49} normal block at 0x00382F78, 40 bytes long. // Data: < > CD CDCD CD CD CD CD CD CD CD CD CD CD CD CD CD //--------------------------------------------------------------------------------- // 顯示信息包含: // 1.內存分配的編號(大括弧中的數字); // 2.內存快的類型(普通型、客戶端型、CRT型); // <1>普通型內存塊是你的程序日常分配的內存類型。 // <2>客戶端型內存塊是MFC程序給須要析構的對象分配的內存塊。 // <3>CRT內存塊是CRT庫爲本身使用而分配的內存塊。 // <4>自由塊,它是已經被釋放的內存塊; // <5>忽略塊,它是已經被特殊標示的內存塊。 // 3.16進製表示的內存位置; // 4.內存快的大小; // 5.前16bytes的內容。 ////////////////////////////////////////////////////////////////////// #if !defined(AFX_DEBUG_H__6B201A16_E36F_4830_A4F5_BD2207106871__INCLUDED_) #define AFX_DEBUG_H__6B201A16_E36F_4830_A4F5_BD2207106871__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // 通常在入口函數cpp中添加如下定義和頭文件 CRT庫 #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> // 內存泄露信息中顯示文件名和代碼行號 #ifdef _DEBUG #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif class CDebug { private: CDebug(); virtual ~CDebug(); public: static void Debug() { // 通常在入口函數一開始添加如下代碼 _CrtDumpMemoryLeaks(); _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); }; // 根據內存分配編號設置斷點: static void Debug(unsigned int num) { //num就是剛剛檢測出來的內存泄露的地方大括號內的數字,跳轉到內存泄露的地方 _CrtSetBreakAlloc(num); } }; #endif //!defined(AFX_DEBUG_H__6B201A16_E36F_4830_A4F5_BD2207106871__INCLUDED_)