C#이나 Java 같은 언어를 사용하는 사람은 메모리 해제에 대해 전혀 신경쓸 필요가 없다. 가비지 컬렉터라는 자동 메모리 관리 기능을 언어 차원에서 지원해주기 때문이다.
하지만 C++은 그렇지 않다. 메모리의 할당도, 할당한 메모리의 해제도, 모두 사용자의 몫이다. 때문에 동적 할당으로 생성된 메모리를 적절한 타이밍에 해제하지 않으면 해당 메모리는 생성된 만큼의 공간을 차지하면서도 정작 사용할 수 없는 상태가 된다. 바로 메모리 누수 현상이다.
그저 new 키워드를 이용해 메모리를 할당한 포인터에 delete 키워드를 적용 시키면 끝나는 얘기지만, 어찌됐든 사용자는 인간이다. 말 그대로 깜박 잊을 수도 있고, 포인터 사이를 이리저리 날아다니는 메모리를 제대로 추적하지 못해 해제하는 타이밍을 놓칠 수도 있다.
메모리 누수 현상을 막는 데는 여러가지 방법이 있지만 그건 다음 포스트에서 알아보기로 하고, 이번 포스트에서는 메모리 누수의 발생 여부를 검사하는 방법을 알아보고자 한다.
#include <iostream>
using namespace std;
int plus(int A, int B) {
int* a;
int* b;
a = new int(A);
b = new int(B);
return *a + *b;
}
void main() {
cout << plus(10,20) << endl;
}
위 소스에 있는 plus 라는 함수는 int형 매개 변수 2개를 받고 있으며, 내부적으로는 int형 포인터 변수를 2개 선언한 후에 거기에 new 키워드를 이용해 메모리를 할당하면서 각각 A와 B 값으로 초기화하고 두 변수의 값을 더해 돌려주고 있다.
보면 알겠지만, plus 함수에서는 new 키워드는 사용됐으나, delete 키워드는 눈을 씻고 찾아봐도 없다. 거기다 포인터를 반환하는 것도 아니기 때문에 함수가 종료되면 사용자는 더이상 손댈 수 없게 된다. 즉, 이 함수를 사용할 때마다 8Byte (int * 2)가 허공으로 사라진다.
이런 단순한 경우는 쉽게 예측이 가능하지만, 조금이라도 소스가 복잡해진다면 메모리 누수가 진행 중인지 아닌 지조차 알 수 없게 되는 경우도 생긴다. 그럴 때는 아래의 방법을 사용하면 된다.
메모리 누수 발생이 의심되는 부분에 작성해도 되긴 하지만 그냥 메인 함수 꼭대기에 써놓는 게 편하다.
4.
디버깅을 시작한다.
4 Bytes * 2 의 메모리가 누수됐다고 출력창에 나온다.
delete 키워드를 추가하면 메모리 누수가 없어졌음을 알 수 있다.
이 방법을 사용하면 디버그 할 때 메모리 누수 발생 여부를 알 수 있지만 어디서 메모리 누수가 발생했는 지는 알 수 없다. 행여 메모리가 포인터 사이를 이리저리 돌아다니는 소스에서 메모리 누수가 발생했다면 문제가 심각해지므로 메모리 누수는 미연에 방지하는 것이 제일 좋다.
반응형
728x90
=======================
=======================
=======================
출처: http://kuaaan.tistory.com/141
디버그 환경에서 재현되는 메모리 릭의 경우 가장 편리하게 디버깅하는 방법은 CRT Debug 함수를 사용하는 것입니다. _CrtSetDbgFlag() API를 사용하면 VS에서 Debug 실행 종료시 DebugString으로 Leak 내용이 출력됩니다. (MFC의 경우 디폴트로 세팅됨) 코드 시작부분에 다음과 같이 선언해주면 함수 종료시 메모리 릭 여부를 체크하여 릭이 있을 경우 아래과 같이 DebugString으로 출력해 줍니다.
Dumping objects -> c:\program files\microsoft visual studio 8\vc\include\crtdbg.h(1150) : {50} normal block at 0x003A2F50, 100 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete. The program '[3868] MemoryLeakTest.exe: Native' has exited with code 0 (0x0).
메시지 중 "{50}"이라는 숫자가 있는데 MSDN에서는 이걸 "Allocation order number"라고 소개하고 있습니다. 말하자면, 50번째로 할당된 메모리에서 Leak이 발생했다는 의미이죠.
이때 _CrtSetBreakAlloc() 함수에 저 번호를 넘겨주면 해당 메모리가 할당된 지점에서 BreakPoint가 걸립니다.
이제 VisualStudio의 CallStack 창에서 해당 메모리가 어디서 할당되었는지 확인만 하시면 되시겠습니다. 단, 위의 함수들은 Debug Only!! ^^ 만약 릴리즈환경에서 오랫동안 실행되어야 확인되는 오류라면 LeakDiag 등 메모리누수 탐지 도구를 사용해야 합니다. 또, 멀티스레드라던가 해서 여러번 실행했을 때 메모리 할당순서가 매번 바뀌는 경우라면 이 방법(CRT Debug함수)은 소용 없을 듯 합니다. 메모리가 할당된 번호를 기준으로 BP를 거니까요..
자세한 내용은 여기에...
http://again4you.egloos.com/1350482
아래 글에서는 CRT 디버그함수를 이용해 메모리누수 뿐만 아니라 delete된 메모리를 재사용하는 오류, 배열의 경계를 침범하는 오류 등을 체크하는 방법도 소개되어 있네요. ^^
- malloc을 재정의 하려는 소스 코드에 아래 라인을 추가. #define malloc DEBUG_MALLOC
위의 방법들로 memory leak dump 에서 할당된 소스 코드와 라인수를 바로 찾을 수 있다.
-------------------------------------------------------------------------------------------------------------------- MFC로 프로젝트 만들어서 디버그하면 프로세스가 종료될 때 메모리 릭을 체크해서 출력창에 보여주는데, 일반 콘솔 어플리케이션이나 WIN32 어플리케이션 프로젝트로 작업하면 그런 정보를 알려주지 않아서 가끔 아쉬울 때가 있다.
그런데.. 이 '메모리 릭 검출 기능'이 MFC 프로젝트에서만 가능한 게 아니라 함수 하나만 호출해 주면 다른 프로젝트에서도 가능하다는 걸 알았다. (이걸 이제서야 알게 되다니...OTL)
덧글|덧글 쓰기