1. 程式人生 > >VS2010檢查記憶體洩露

VS2010檢查記憶體洩露

VS2010中的C++程式記憶體洩露檢測

    MFC程式是支援記憶體檢測的。對於非MFC程式而言,CRT有一套記憶體洩露的函式,最常用的是 _CrtDumpMemoryLeaks();如下所示:

#include <crtdbg.h>
int main() {
	int *pInt = new int();
	char *pChar = new char();
	double *pDouble = new double();
	// position 1
	_CrtDumpMemoryLeaks();

	return 0;
}
    執行之後,結果如圖1所示:

   可以看到,在第71次({71})分配記憶體時發生了洩露,略有不足的是,沒有顯示出是哪一行導致的記憶體洩露。將#include <crtdbg.h>(<crtdgb.h>必須被包含)改為如下:

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
    執行之後,結果如圖2所示:


    可以看到是因為main.cpp的第16行導致了4 bytes的記憶體洩露,第17行...第18行...

    但是這段程式碼仍然存在一些問題,例如_CrtDumpMemoryLeaks()放在position 1時,雖然接下來使用delete釋放new分配的記憶體,但是執行後結果與圖2仍然相同。如下所示:

int main() {
	int *pInt = new int();
	char *pChar = new char();
	double *pDouble = new double();
	// position 1
	_CrtDumpMemoryLeaks();

	delete pInt;
	delete pChar;
	delete pDouble;	
	//position 2
//	_CrtDumpMemoryLeaks();
	return 0;
}
    最好的辦法是將_CrtDumpMemoryLeaks()放置在函式的出口處(如position 2處)。

    這個方法對於C++中由程式設計師自定義的類物件建立和銷燬是不夠正確的,如下所示:

class Apple {
public:
	Apple(){ ptr = new char(); }
	~Apple(){ delete ptr; }
	char *ptr;
};

int main() {
	int *pInt = new int();
	char *pChar = new char();
	double *pDouble = new double();
	// position 1
//	_CrtDumpMemoryLeaks();
	Apple app;

	delete pInt;
	delete pChar;
	delete pDouble;	
	//position 2
	_CrtDumpMemoryLeaks();
	return 0;
}
    執行結果如圖3所示:


    其中第17行的程式碼為

	Apple(){ ptr = new double(); }
    可以看到即使類Apple中定義了解構函式釋放記憶體,但是position 2處的_CrtDumpMemoryLeaks();仍然給出了記憶體洩露的資訊。

    改進的方法就是在分配記憶體之前使用_CrtSetDbgFlag()函式(_CrtSetDbgFlag()可以在程式退出時呼叫_CrtDumpMemoryLeaks()),如下所示:

 int _CrtSetDbgFlag( int newFlag );
    newFlag的引數如下所示(詳見_CrtSetDbgFlag函式介紹MSDN的_CrtSetDbgFlag函式):
Bit field Default Description
_CRTDBG_ALLOC-
_MEM_DF
ON ON: Enable debug heap allocations and use of memory block type identifiers, such as_CLIENT_BLOCK.
OFF: Add new allocations to heap’s linked list, but set block type to _IGNORE_BLOCK.
_CRTDBG_CHECK-
_ALWAYS_DF
OFF ON: Call _CrtCheckMemory at every allocation and deallocation request.
OFF: _CrtCheckMemory must be called explicitly.
_CRTDBG_CHECK-
_CRT_DF
OFF ON: Include _CRT_BLOCK types in leak detection and memory state difference operations.
OFF: Memory used internally by the run-time library is ignored by these operations.
_CRTDBG_DELAY-
_FREE_MEM_DF
OFF ON: Keep freed memory blocks in the heap’s linked list, assign them the_FREE_BLOCK type, and fill them with the byte value 0xDD.
OFF: Do not keep freed blocks in the heap’s linked list.
_CRTDBG_LEAK-
_CHECK_DF
OFF ON: Perform automatic leak checking at program exit via a call to_CrtDumpMemoryLeaks and generate an error report if the application failed to free all the memory it allocated.
OFF: Do not automatically perform leak checking at program exit.
int main() {
	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	int *pInt = new int();
	char *pChar = new char();
	double *pDouble = new double();
	// position 1
//	_CrtDumpMemoryLeaks();
	Apple app;

//	delete pInt;
	delete pChar;
	delete pDouble;	
	//position 2
//	_CrtDumpMemoryLeaks();
	return 0;
}
    執行結果如圖4所示:

    正確的指出了pInt指向的記憶體沒有釋放,類Apple的正確行為不再顯示。

    如果將Apple類的解構函式變化一下

	~Apple(){ delete ptr; }
    變為:
	~Apple(){  }
   執行結果如圖5所示:


    可以看到_CrtSetDbgFlag()函式正確地指出了Apple類物件的記憶體沒有釋放