[Visual C++] crtdbg를 이용한 (Memory leak) 메모리 누수 탐지 [출처] [Visual C++] crtdbg를 이용한 (Memory leak) 메모리 누수 탐지|작성자 SwimRun

2014. 1. 3. 09:47C++



1) Definition crtdbg 정의
우선 다음의 정의를 보통 어플리케이션 시작 부분 .cpp 상단에 입력 해줌으로 crtdebug.h의 메모리 할당 추적할 것임을 정의.

#define CRTDBG_MAP_ALLOC 
#include <stdlib.h> 
#include <crtdbg.h>


#ifdef _DEBUG

#define new new( _NORMAL_BLOCK, __FILE__, __LINE__ )   // #include <new.h>등으로 operator new나 malloc을 

                                                                                       // Derived해서 정의 한 경우, 사용 할 수 없다.

#endif


crtdbg.h를 포함하여, 메모리 할당과 할당 취소를 추적하는 해당 디버그 버전, _malloc_dbg 및 _free_dbg에 new operator의
malloc와 free 함수를 매핑하며, 이 정의는 디버그 _DEBUG 모드에서만 작동한다.
릴리즈 빌드에서는 일반적인 malloc 함수와 free 함수가 사용된다.

2) 메모리 누수 정보 알기. _CrtDumMemoryLeaks(); 
_CrtDumpMemoryLeaks();  문을 릭이 발생한 다음 부분에 추가하여 메모리 누수가 일어 났는지에 대한 반환값을 
TRUE / FALSE로 알 수 있고 누수가 일어난 경우 Leak List를 출력(Output)창에 출력해준다.
보통 코드 어플리케이션의 끝 부분 .cpp 함수 하단에 입력 해줌으로 결과를 알 수가 있다.

ex) 다음 코드는 릭이 발생한 경우 "Memory Leak? 1" / 발생하지 않은 경우 "Memory Leak? 0" 이 출력

int main()
{
...
string outputMemoryLeaks = "Memory Leak? " 
+ std::to_string(static_cast<LONGLONG>(_CrtDumpMemoryLeaks()));
MessageBox(NULL, outputMemoryLeaks.c_str(), "MemoryLeak", MB_OK);

return EXIT_SUCCESS;
} //

ex) Output 출력 메모리릭 _CrtDumpMemoryLeaks() 결과 화면


{160}, {139}, {137}...는 메모리 할당된 순서이다.
이는 메모리 릭이 발생한 블럭(변수) 위치점을 추적할 때 필요하므로 알아둔다. 

Detected memory leaks!
Dumping objects ->
{160} normal block at 0x00875B58, 1840 bytes long.
 Data: <|               > 7C 8B E7 00 CD CD CD CD CD CD CD CD CD CD CD CD 

{160} : 메모리 할당 번호(중괄호 안에 표시)
normal block : 블록 형식(표준, 클라이언트 또는 CRT)
0x00875B58 : 16진수로 표기한 메모리 위치
1840 bytes long : 릭 발생 블록 크기 바이트로 표기
7C 8B E7 00 CD CD CD CD CD CD CD CD CD CD CD CD : 16진수로 표기한 처음 16바이트의 내용

3) 메모리 누수 정보 알기. _CrtSetDbgFlag(DEBUG_FLAG); 
프로그램이 종료될 때 자동으로 _CrtDumpMemoryLeaks() 를 호출하여 주는 방법으로 Function Scope에 구애받지 않을 수 있다.
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
프로그램 최초 시작점에 코드 기술 해준다. DEBUG_FLAG들 참고

ex)
/// CRT_DBG
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

int main(void)
{
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
...
}

ex) _CrtSetDbgFlag 로 자동 덤프메모리릭 출력 화면


5) 릭 위치점 알기. _CrtSetBreakAlloc( 릭발생 위치점 );
{160} normal block at 0x00875B58, 1840 bytes long. 
릭 위치점 160을  _CrtSetBreakAlloc(160); 입력, 프로그램 시작 점에 추가시켜 Debug모드 상에서 실행 시키면 160번째 
메모리 할당되는 시점에 BreakPoint가 걸리고 CallStack으로 해당 변수를 확인 할 수 있다.
int main()
{
//_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetBreakAlloc( 160 );
...
}



ex) Leak Breakpoint Function Call Stack.

Call Stack 창이 뜨고 CSingleton_<CFilePathUtil> 을 할당했지만 Destruction 되지 않았음을 알 수 있다.

ex) Fix memory leak.


이상 코드는 https://github.com/egoquat/RandomDistributionTest 의 Application/main.cpp에 작업되었다.

참고 : http://blog.naver.com/hermet?Redirect=Log&logNo=54353236  // C Runtime 환경의 메모리 릭 잡는 방법 ( Memory Leak )
참고 : http://msdn.microsoft.com/ko-kr/library/x98tx3cf.aspx   // CRT 라이브러리를 사용하여 메모리 누수 찾기
참고 : http://msdn.microsoft.com/ko-kr/library/e5ewb1h3(v=vs.80).aspx // 메모리 누수 탐지 기능 사용
참고 : http://www.gamedevforever.com/282  // 비쥬얼 스튜디오 디버깅 팁 ( Visual Studio Debugging Tips )
참고 : http://littles.egloos.com/3383811  // Windows 메모리/리소스 누수 디버깅 기법들