간단히 메모리 릭 발생여부를 알아내고 이를 해결하는 방법에 대해서 알아봅시다.
이는 MS 사에서 CRT(C Runtime) 라이브러리로 제공해는 CRTDBG 를 이용할 겁니다.
생각보다 쉬운 반면 그 기능은 막강하지요.
일단 프로그램 정의부에 다음과 같이 추가합니다.
#define CRTDBG_MAP_ALLOC
#ifdef _DEBUG
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__ ) //궁금하시면 제 게시글 중 <매크로 마법> 편을 보세요.
#endif
이제 메인 진입 부 처음에 다음과 같이 선언합니다. 일반 main() 이라고 가정합니다. 물론 WinMain() 일 수도 있습니다.
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
// .... 메모리를 동적 할당하는 무언가의 작업을 하겠죠
}
추가로 설명하자면, _CrtSetDbgFlag 설정 비트 필드 값은 다음과 같습니다.
_CRTDBG_ALLOC_MEM_DF : 디버그 힙 메모리 할당을 허용합니다. 또한 _CLIENT_BLOCK과 같은 사용자 정의 메모리 블럭을 사용합니다.
_CRTDBG_LEAK_CHECK_DF : 프로그램 종료 시 자동으로 메모리 릭을 찾고 이를 출력해 줍니다. 이는 _CrtDumpmemoryLeaks 함수를 호출한 것과 같은 결과입니다.
이제 프로그램을 디버그 모드로 실행하고 종료합니다. 만약 동적 메모리 해제를 제대로 안해줬다면 다음과 같은 결과가 결과 화면에 출력됩니다.
우리에게 필요한 것은 바로 빨간색 선을 그은 정보입니다. 우리는 이 번호를 이용해 메모리 릭이 일어나는 부분을 찾아갈 수 있습니다.
그러나 중요한 점은 똑같은 환경에서 다시 실행했을 때도 메모리 릭 현상 결과가 같아야 한다는 점입니다. 그렇지 않으면, 매번 실행할 때마다 메모리 릭이 발생한 위치가 달라지고 따라서 위 번호도 달라져 버립니다. 따라서, 다른 작업을 하지 마시고 디버깅 작업만 하시길 바랍니다.
일단 위 9637 번호를 이용해서 메모리 릭이 일어나는 곳을 찾아가겠습니다. 이제 다시 main 첫부분에 다음과 같이 추가합니다.
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetBreakAlloc( 9637 );
// .... 메모리를 동적 할당하는 무언가의 작업을 하겠죠
}
그리고 다시 디버그 모드로 실행을 하면 9637에 지시하는 똑같은 메모리 번지를 알아서 브레이크 포인터를 걸어줍니다.
우리는 그 부분의 소스를 보고 콜 스택을 추적해 가면서 메모리 릭을 감지하고 해결할 수가 있죠.
이런식으로 출력창에 출력되었던 다른 메모리 릭도 모두 찾아 해결하시면 됩니다.
릴리즈 배포 전, 메모리 책임은 프로그래머의 미덕이지 않을까요?
근데 VS 2008은 이게 항상 동작하나보다.
디버그 모드 실행 -> 테스트 -> 프로그램 종료하면 메모리 릭 발생한 리스트가 output에 뜬다.