2008년 10월 05일
delete this;를 통해 알아보는 클래스의 메모리 접근 메커니즘

delete this; 라는 코드를 혹 보신적 있으신가요? 저는 최근 CWinThread 클래스를 사용하던 중 이 코드를 처음 봤는데요. delete this;를 통해 CWinThread 클래스의 객체가 메모리에서 해제 된 후에도 CWinThread 클래스의 멤버함수의 호출이 정상적으로 이루어지는 현상을 발견하였습니다. 물론 함수 내부의 변수에 접근할 때 Access violation 에러를 발생하며 프로그램이 종료되기는 했지만 말이죠 ~ 그럼 왜 이런 일이 가능했을까요? 객체가 메모리에서 해제 되면 당연히 클래스의 멤버에 접근할 수 없는 것 아니었나요?? 그럼 이 내용에 대해서 연구를 해보겠습니다.

일단, 아래의 코드를 실행해 보면 위에서 제가 설명 드렸던 부분이 어떤 현상을 이야기 하는 것인지 직관적으로 알 수 있습니다.
CTest 클래스의 멤버 변수를 보면(1번 박스) 일반 변수와 정적 변수로 구성되어 있는 것을 알 수 있습니다.(엄연히 이야기 하면 m_iVal은 멤버 변수이고 iStaticVal은 클래스 변수라고 부르는게 맞겠죠 ^^) 2번 박스의 ShowData() 멤버 함수는 이들 변수를 화면에 출력해주고 SelfDelete()함수는 자기자신의 메모리를 해제해 줍니다.

main 함수를 보면 CTest클래스를 생성한 후 바로 SelfDelete()함수를 통해 자기자신의 메모리를 해제한 후에 ShowData()함수를 호출하고 있는 것을 알 수 있습니다.


그럼 과연 결과는 어떻게 나왔을까요? 아래 결과를 보시면 메모리가 해제 되었기 때문에 멤버변수인 m_iVal의 값은 쓰레기 값으로 체워졌지만 ShowData() 멤버 함수에 정상적으로 접근하여 각 변수의 값을 보여주고 있습니다.

이것은 무엇을 의미하는 걸까요?? 일단 정적변수의 경우는 main함수가 호출되기도 전에 프로세스가 메모리에 올라가는 시점에서 함께 메모리에 올라가게 됩니다. 즉 CTest를 메모리 생성을 하건 안하건 상관 없이 이미 메모리에 올라가 있는 것이지요. 반면에 멤버 변수인 m_iVal의 경우는 클래스의 멤버 변수이기 때문에 CTest를 메모리에 올리기 전에는 접근할 수 없게 되는 것이며 위와 같이 SelfDelete()를 호출하여 메모리를 해제 한 후 호출 되었을때는 쓰레기 값이 출력되는 것이죠. 그렇다면 메모리가 해제 되었는데 ShowData() 멤버 변수에는 어떻게 접근했을까요?? ShowData()와 같은 어떤 동작을 위한 함수 등은 메모리의 코드영역이란 곳에 올라가게 되는데 이 영역 또한 정적 변수가 올라가는 데이터 영역과 같이 프로세스가 실행 되는 시점에서 모두 메모리에 올라가기 때문에 가능한 것입니다.

위 설명을 간단히 프로세스가 메모리에 올라 갈 때 메모리 영역 단위로 나눈 그림으로 보면 아래와 같은데요. 아래 그림의 빨간 원안에 들어가 있는 영역들은 프로세스가 메모리에 올라 갈 때 함께 메모리에 올라가 프로세스가 종료 될 때 함께 메모리에서 내려오는 영역들입니다.

그럼 코드영역이 프로세스가 이미 메모리에 올라 갈때 함께 모두 올라간다고 했으니까 아래와 같은 시나리오가 연상 될 수 있습니다. 만약 CTest 클래스의 메모리 생성을 한 m_pTest변수 자체의 메모리를 해제 한 후 ShowData() 멤버 함수에 접근하면 어떻게 될까요?? 호출이 되어야 하지 않을까요?? 당연히 호출이 됩니다. 하지만 재미있는 결과가 기다리고 있습니다.

위와 같은 결과가 나온 이유가 뭘까요?? 이는 ShowData()함수의 내부를 봐야하는데요. 내부에서 보면 m_iVal에 접근하고 있습니다. 하지만 pTest 자체는 이미 NULL 포인터를 가리키고 있기때문에 m_iVal이 어디있는지 알 수 없죠?? 그에 비해 ShowData() 멤버 함수나 클래스 변수(정적 변수)인 iStaticValue는 이미 메모리에 올라가 있으니 어디에 있는지 알 수 있습니다. 그럼 ShowData() 멤버변수에서 m_iVal에 접근하는 코드는 제거 한 후 실행하면 어떻게 될까요??


어때요?? 증명이 되죠?? ㅎㅎ

위 연구를 통해 클래스의 메모리 접근 메커니즘을 정리해 보면 가장 중요한 개념은 프로세스가 메모리에 올라갈 때 함께 올라가는 메모리 영역에 해당하는 데이터들이 무엇이고 프로세스가 메모리에서 내려갈 때 함께 내려가는 메모리 영역에 해당하는 데이터들이 무엇이냐는 것입니다. 데이터 영역과 코드 영역의 경우가 이에 해당하기 때문에 이 영역들에 위치하게 되는 데이터들은 언제든지 접근이 가능한 것이지요. 물론 위 ShowData()에서 봤던 것 처럼 이미 메모리에 올라와 있는 영역이라 할지라도 그 안에서 접근하는 데이터가 스택이나 힙영역에 있다면 이 영역에 해당하는 데이터가 메모리에 올라와 있지 않으면 Access 오류가 발생할 수 있다는 것입니다.

그럼 한가지 더 재미있는 결과를 보고 이번 포스팅을 마치도록 하겠습니다.

이번에는 CTest클래스를 생성도 하지 않은체 ShowData()를 호출해 보았습니다. 어떻게 됐을까요?? 우리는 이미 답을 알고 있습니다. 정상적으로 호출되고 iStaticVal의 값을 화면에 출력해 줍니다. ^^


by greenfrog | 2008/10/05 12:26 | C++ / WIN32 / MFC | 트랙백 | 덧글(0)
트랙백 주소 : http://greenfrog7.egloos.com/tb/913381
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글



<< 이전 페이지 | 다음 페이지 >>