메모리 동적 할당 후 해제를 따로 하지 않아도 에러가 발생하지 않기에 누수 발생 여부를 알기 어렵다.
이때, CRT 라이브러리를 이용하면 다음과 같이 디버깅 시 누수 지점을 쉽게 찾을 수 있다.
Detectd memory leaks!
우선 다음과 같은 선언이 필요하다.
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define 문은 메모리 누수 결과를 더 자세히 보여주도록 하는 정의문이라고 하는데 나의 경우 결과가 동일했다.
실제로 더 자세히 보여주기 위해선 new 연산자를 추가 인자와 함께 매크로로 정의하여 몇 가지 정보를
더 출력하도록 해야했다. 그 방법은 잠시 후 소개하고, 결과가 동일해도 혹시 모르니 위와 같이 작성한다.
다음은 누수를 탐지하기 위한 함수들이다. 복잡해보일 수 있는데 사용해보면 전혀 복잡하지 않다.
_CrtDumpMemoryLeaks();
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
_CrtSetBreakAlloc()
_crtBreakAlloc
_CrtDumpMemoryLeaks()
_CrtSetDbgFlag()
두 함수는 메모리 누수 결과를 디버그 결과 창에 표시해준다.
첫 번째 함수는 메모리 문제로 인해 프로그램이 종료되는 지점에 사용하는데, 첫 누수 결과만 출력한다. 여러 군데가 있다면 군데군데서 함수를 호출해야하는 번거로움이 있다. 따라서 두 번째 함수를 사용한다. 두 번째 함수는 프로그램의 시작 부분에 한 번 사용하면 탐지 가능한 모든 누수를 결과 창에 표시한다.
_CrtSetReportMode()
세 번째 함수는 결과(보고서)의 출력 방식을 설정한다. 파일에도 설정할 수 있으며 assert처럼 경고 창으로 띄울 수도 있다.
이 함수는 따로 사용하지 않아도 기본으로 결과 창엔 출력되기 때문에 추가로 설정하고 싶다면 다음 링크를 참고하자.
https://docs.microsoft.com/ko-kr/cpp/c-runtime-library/reference/crtsetreportmode?view=vs-2019
_CrtSetBreakAlloc()
_crtBreakAlloc
네 번째는 함수이고 다섯 번째는 매크로인데, 둘 다 동일한 기능을 한다.
누수 발생 시 보고서에 누수 지점의 번호가 출력되는데, 그 번호를 해당 함수의 인자로 전달하면 그 지점에서 멈춘다.
그럼 아래 코드에서 발생하는 누수를 찾아보자.
void main()
{
int* ptr = new int[10];
}
위와 같이 _CrtSetDbgFlag 또는 _CrtDumpMemoryLeaks() 함수를 통해 결과를 출력한다.
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
void main()
{
// 메모리 누수 발생 시 그 지점 정보를 출력하도록 한다.
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
int* ptr = new int[10];
// _CrtDumpMemoryLeaks();
}
결과는 다음과 같이 누수를 찾았다면 Detected memory leaks! 와 함께 탐지한 정보들이 출력된다.
{ 159 }
누수 정보 중 처음으로 나오는 정보인데 할당된 메모리 번호(지점)을 의미한다.
이 지점이 어디인지 알고 싶다면 _CrtSetBreakAlloc() 또는 _crtBreakAlloc 매크로를 통해 이 번호를 전달하여 찾을 수 있다.
normal block
해당 메모리 영역의 블럭 형식이다. 블럭 형식은 normal / client / CRT로 나뉘며 normal은 보통 new 연산자로 할당된 메모리이다. client는 MFC 관련, CRT는 CRT 라이브러리 자체 용도에 맞게 할당된 블록이다.
0x00B95F50
누수가 일어난 메모리 주소, 즉 ptr의 값이다. 그리고 40 bytes는 할당된 메모리 크기이다.
CD CD CD ...
해당 주소의 첫 16바이트 값을 16진수로 나타낸 것이다.
현재 쓰레기 값이 들어있으므로 CD로 나오지만, ptr[0]에 3이 저장되어 있다면 03 00 00 00 CD CD CD CD....와 같이 출력된다.
이제 메모리 번호를 이용하여 해당 지점을 찾아보자.
아래와 같이 _CrtSetBreakAlloc() 함수를 추가한다. 메모리 할당 전에 호출해야한다.
그리고 코드를 추가하거나 변경하면 메모리 번호가 변경될 수 있으므로 메모리 번호의 변경여부를 다시 한번 확인한다.
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
void main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetBreakAlloc(159);
int* ptr = new int[10];
}
그러면 다음과 같이 누수된 메모리를 할당한 지점에서 멈춘다.
다음은 탐색 결과가 더 자세히 나오도록 매크로를 이용하는 것인데 어차피 Crt Break함수를 통해 찾을 수 있으므로 참고만 하자.
new 연산자에 인자를 추가하여 DBG_NEW 라는 매크로를 만들어 사용한다.
new 대신 DBG_NEW로 메모리를 할당하면 Debug 모드에선 custom new가 실행되고 Release 모드에선 알아서 일반 new가 실행된다.
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#else
#define DBG_NEW new
#endif
void main() {
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
const char* str = DBG_NEW char[20];
}
위처럼 하면 결과가 다음과 같이 파일 이름과 라인 번호까지 출력된다.
'C,C++ > Debugging things' 카테고리의 다른 글
Visual studio 디버거 덤프 파일 생성 (0) | 2023.10.08 |
---|---|
dumpbin을 사용하여 .lib 파일 내의 함수 정보 얻기 (0) | 2023.04.27 |
윈도우 메모리 릭 디버깅 슬라이드셰어 (0) | 2021.10.04 |
[c++] Visual studio 2019 환경에서 디버깅 하기 / debugging, memory, disassemble, 디버그, 디버거 (0) | 2019.10.15 |
댓글