[110] C++ 메모리 누수 확인, new/delete Memory Leak Check
초보자를 위한 C++ 200제 독자 포스트 : 이준우님 질문의 답변입니다.
질문 글
110번 예제 보는 중에 궁금한 게 생겼는데요?
class 안에서 변수에 메모리를 동적 할당/해제 하셨는데, 혹시 변수 메모리 할당만 하고 class 자체를 delete하면 할당된 변수의 메모리도 해제되나요??
우선 비주얼스튜디오에서 C++ 메모리 누수 확인할 방법을 소개합니다. 책에서도 소개할 걸 그랬네요.
우선 아래 코드를 봐주세요.
#include “stdafx.h“#include <iostream>#include <crtdbg.h>using namespace std;#ifndef _DEBUG#define new new(_CLIENT_BLOCK,__FILE__,__LINE)#endifclass TestClass{public:TestClass(){data = new double[3];data[0] = 0;data[1] = 1;data[2] = 2;}~TestClass(){delete data;}private:double* data;};int main(){_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);TestClass *tc = new TestClass();delete tc;return 0;}
- 3번 라인 : crtdbg.h 파일을 추가합니다.
- 7~9번 라인 : Debug 모드에서 수행할 #define 지시문 코드를 삽입합니다.
- 31번 라인 : 메모리 누수 확인할 수 있는 코드를 삽입합니다.
위 코드를 추가하면, 프로그램 종료 시 비주얼스튜디오 하단 출력창에 메모리 누수 확인 항목이 출력됩니다.
1. 이어서 질문으로 돌아가면, 결론적으로 소멸자에서 명시적으로 delete 해주지 않으면 메모리 해제가 되지 않습니다.
가령 TestClass* tc = new TestClass();라고 선언하면 tc는 객체를 가리키는 포인터로 4바이트를 갖습니다. 내부 요소는 주소를 참조하여 가리키게(->) 됩니다. 즉, 메모리 어딘가에 할당된 TestClass 객체와 tc 사이엔 포인터가 존재합니다.
그리고 포인터는 delete 하더라도 원래 가리키던 곳(TestClass 객체의 메모리 주소)을 가리킵니다. 그래서 포인터를 delete하고 NULL로 설정하면 메모리 오염도 방지할 수 있습니다.
2. 메모리 구조는 포함하는 개념이 아니라 층으로 쌓여있는 개념입니다.
그래서 한 메모리 영역이 다른 메모리 영역을 포함한다기보단 참조하는 개념이죠. 그래서 한 메모리 영역을 해제했다고 해서 다른 메모리 영역까지 해제될 순 없습니다. 거꾸로 생각해보면, 내가 10001 번지를 delete했는데 컴파일러가 잘못 유추해 10002 번지를 delete 해버리면 되게 위험하겠죠.
그래서 일일이 delete 해줘야 합니다.
찬가지로 위 코드는 에러가 발생하지 않지만, 22번 또는 34번 라인을 주석 처리하면 메모리 누수가 발생합니다. delete를 시도할 때 컴퓨터는 알아서 소멸자를 호출하는데 이때, 소멸자에 delete 코드, 그러니깐 메모리 해제 코드가 있어야 합니다.
안 그러면 아래처럼 좋지 않은 메모리 누수 확인 결과가 출력됩니다.
double data 배열은 크기가 3이라 3 * 8 = 24 바이트 누수가 발생합니다. 결론은 … 일일이 해제해야 합니다. 그러지 않고 메모리 누수 확인하면 좋지 않은 결과가 눈에 보일 겁니다. 더 궁금한 사항은 언제든 댓글로 알려주세요.
책에 관심있으시다면, 아래 링크에서 상세 설명 보세요.
Release, Remove, Dispose, Clear, UnInitialize, de-Initialize, Terminate, Detonate 등 여러 가지 표현 방법이 있는데 저는 Dispose를 선택했습니다. 그냥 살다 보니 그게 익숙해서 선택한 것이죠. 가끔 이런 쓸데없는 고민해 보는 것도 재밌긴 해요.