메모리 누수를 탐지하는 데 사용하는 기본 도구는 디버거와 CRT(C 런타임 라이브러리) 디버그 힙 함수입니다.
디버그 힙 함수를 사용하려면 다음 문이 프로그램에 포함되어 있어야 합니다.
#define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h>
CRT 함수가 제대로 작동하려면 #include 문이 여기에 표시된 순서를 따라야 합니다.
crtdbg.h를 포함하면 malloc 및 free 함수가 해당 디버그 버전인 _malloc_dbg 및 free에 매핑되어 메모리 할당 및 할당 해제를 추적할 수 있습니다. 이 매핑은 _DEBUG가 있는 디버그 빌드에서만 발생합니다. 릴리스 빌드에서는 일반적인 malloc 함수와 free 함수가 사용됩니다.
#define 문은 CRT 힙 함수의 기본 버전을 해당 디버그 버전에 매핑합니다. #define 문을 생략하면 메모리 누수 덤프가 덜 자세하게 표시됩니다.
이러한 문을 사용하여 디버그 힙 함수를 사용하도록 설정한 후에는 응용 프로그램 종료 지점 앞에_CrtDumpMemoryLeaks 호출을 추가하여 응용 프로그램이 종료될 때 메모리 누수 보고서를 표시할 수 있습니다.
_CrtDumpMemoryLeaks();
응용 프로그램의 종료 지점이 여러 개인 경우 각 종료 지점마다 _CrtDumpMemoryLeaks 호출을 수동으로 추가할 필요는 없습니다. 응용 프로그램의 시작 부분에 있는 _CrtSetDbgFlag 호출로 인해 각 종료 지점마다 _CrtDumpMemoryLeaks가 자동으로 호출되기 때문입니다. 다음과 같이 두 개의 비트 필드를 설정해야 합니다.
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
기본적으로 _CrtDumpMemoryLeaks는 출력 창의 디버그 창에 메모리 누수 보고서를 출력합니다._CrtSetReportMode를 사용하여 이 보고서를 다른 위치로 리디렉션할 수도 있습니다.
라이브러리를 사용할 경우에는 라이브러리에 의해 출력이 다른 위치로 다시 설정될 수도 있습니다. 이 경우 다음과 같이 출력 위치를 출력 창으로 다시 설정할 수 있습니다.
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
응용 프로그램에 _CRTDBG_MAP_ALLOC이 정의되지 않은 경우 _CrtDumpMemoryLeaks는 다음과 같은 메모리 누수 보고서를 표시합니다.
Detected memory leaks! Dumping objects -> {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.
응용 프로그램에 _CRTDBG_MAP_ALLOC이 정의된 경우에는 메모리 누수 보고서가 다음과 같이 표시됩니다.
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.
두 번째 보고서에는 누수된 메모리가 처음 할당된 파일 이름 및 줄 번호가 표시된다는 차이점이 있습니다.
_CRTDBG_MAP_ALLOC의 정의 여부에 관계없이 메모리 누수 보고서에 항상 표시되는 정보는 다음과 같습니다.
메모리 할당 번호(이 예제의 경우 18)
블록 형식(이 예제의 경우 normal)
16진수 메모리 위치(이 예제의 경우 0x00780E80)
블록 크기(이 예제의 경우 64 bytes)
블록 내 데이터의 처음 16바이트(16진수 형식)
메모리 누수 보고서에서는 메모리 블록을 표준 블록(normal block), 클라이언트 블록(client block) 또는 CRT 블록(CRT block)으로 식별합니다. 표준 블록은 프로그램이 할당한 보통 메모리입니다. 클라이언트 블록은 MFC 프로그램이 소멸자를 필요로 하는 개체에 대해 사용하는 특별한 메모리 블록 형식입니다.MFC new 연산자는 표준 블록 또는 클라이언트 블록 중 생성되는 개체에 적합한 블록을 만듭니다. CRT 블록은 CRT 라이브러리가 자체 용도에 맞게 할당한 메모리 블록입니다. 이러한 블록의 할당 해제는 CRT 라이브러리에서는 처리됩니다. 따라서 CRT 라이브러리 손상 같은 중대한 문제가 발생하지 않는 한 메모리 누수 보고서에 이 블록이 표시되는 경우는 거의 없습니다.
그 외에도 메모리 누수 보고서에 표시되지 않는 두 가지 메모리 블록 형식이 있습니다. 빈 블록은 해제된 메모리로, 정의에 따라 누수되지 않은 메모리를 나타냅니다. 무시 블록은 메모리 누수 보고서에서 제외하도록 사용자가 명시적으로 지정한 메모리입니다.
이러한 기술은 표준 CRT malloc 함수를 사용하여 할당된 메모리에 대해 작동합니다. 프로그램에서는 C++ new 연산자를 사용하여 메모리를 할당하지만, 메모리 누수 보고서에 파일 및 줄 번호를 표시하려면 new를 다시 정의해야 합니다. 이 작업에는 다음과 같은 코드 블록을 사용할 수 있습니다.
#ifdef _DEBUG #ifndef DBG_NEW #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) #define new DBG_NEW #endif #endif // _DEBUG
메모리 할당 번호는 누수된 메모리 블록이 할당된 시기를 알려 줍니다. 예를 들어 메모리 할당 번호가 18인 블록은 응용 프로그램 실행 도중 18번째로 할당된 메모리 블록입니다. CRT 보고서에서는 실행 중의 모든 메모리 블록 할당 횟수를 계산합니다. 여기에는 CRT 라이브러리와 MFC 등의 다른 라이브러리에 의한 할당이 포함됩니다. 따라서 메모리 할당 번호가 18인 블록은 코드에서 18번째로 할당된 메모리 블록이 아닐 수도 있습니다. 대개는 이 경우에 해당됩니다.
할당 번호를 사용하여 메모리 할당에 중단점을 설정할 수 있습니다.
조사식 창을 사용하여 메모리 할당 중단점을 설정하려면
응용 프로그램의 시작 부분에 중단점을 설정하고 응용 프로그램을 시작합니다.
응용 프로그램이 중단점에서 중단되면 조사식 창을 실행합니다.
조사식 창에서 이름 열에 _crtBreakAlloc을 입력합니다.
CRT 라이브러리의 다중 스레드 DLL 버전을 사용할 경우(/MD 옵션){,,msvcr100d.dll}_crtBreakAlloc과 같이 컨텍스트 연산자를 포함해야 합니다.
RETURN 키를 누릅니다.
디버거에서 호출이 실행되고 결과가 값 열에 표시됩니다. 메모리를 할당할 때 중단점을 설정하지 않은 경우에는 이 값이 –1입니다.
값 열에서 표시된 값을 중단할 메모리 할당의 할당 번호로 대체합니다.
메모리 할당 번호에 중단점을 설정한 후 디버깅을 계속할 수 있습니다. 이전과 같은 조건에서 프로그램을 실행하려면 메모리 할당 순서가 변경되지 않도록 주의하십시오. 지정된 메모리 할당에서 프로그램이 중단되면 호출 스택 창과 다른 디버거 정보를 사용하여 메모리가 할당된 조건을 확인할 수 있습니다. 그런 다음 실행을 계속하여 개체에 발생한 상황을 살펴보고 메모리가 올바르게 할당 해제되지 않은 원인을 확인할 수 있습니다.
개체에 데이터 중단점을 설정하는 것도 유용합니다. 자세한 내용은 방법: 데이터 중단점 설정(네이티브 전용)을 참조하십시오.
코드에서 메모리 할당 중단점을 설정할 수도 있습니다. 여기에는 두 가지 방법이 있습니다.
_crtBreakAlloc = 18;
또는
_CrtSetBreakAlloc(18);
=======================================================================
정리 하자면 미리컴파일된 헤더 사용시에는 그곳에 아니면 인클루드 된 헤더에
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
추가해주고
new or malloc 을 사용하는 cpp 파일 상단에
#if _DEBUG #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) #endif 추가.. 그리고 프로그램 시작 부분에 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); 추가해주면 된다!
'Programming > C, C++, MFC' 카테고리의 다른 글
Device Context ( DC ) (1) | 2013.08.06 |
---|---|
GetDlgItem() 함수를 이용하기 (0) | 2013.07.03 |
CFileDialog 다중파일 선택하기 (0) | 2013.06.14 |
#define 에 관한 내용 (0) | 2013.06.07 |
MFC TabControl 사용법 (2) | 2013.04.30 |