2010. 4. 20. 03:45

알수없는 위치에 메모리릭이 발생하는 경우 검출법(vs2008기준)


다음과 같은 구문을 활용해 메모리 릭을 검출하는 경우(혹시 아래와 같은 구문을 처음 보신다면 메모리릭검출을 검색해서 관련부분을 살펴보고 오세요.)

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

// 출력창으로 정보를 출력시킨다.
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG  );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG  );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG  );

#define DEBUG_NORMALBLOCK new ( _NORMAL_BLOCK, __FILE__, __LINE__ )
#ifdef new
#undef new
#endif
#define new DEBUG_NORMALBLOCK


이런 케이스나
c:\test\test.cpp(9) : {228} normal block at 0x00666458, 4 bytes long.
 Data: <    > CD CD CD CD

이런 케이스로 메모리릭이 났다는 것을 알려준다.
{81253} normal block at 0x03BB0AD0, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

첫번째의 경우 파일명, 라인까지 친절하게 알려주기 때문에 메모리릭을 잡는데 어려움이 없지만
두번째의 경우 파일명과 라인이 없어 다소 당황스러울 수도 있다.(당연히 나올거라 예상했을거에요...)
하지만 이를 해결하기 위한 기타 여러가지 정보들이 있다.

다시 두번째 케이스를 보면,
{81253} normal block at 0x03BB0AD0, 16 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

여기서 81253는 몇번째로 할당했는가를 나타낸다. 그리고 0x03BB0AD0 주소에서 릭이 발생했다는 것을 알 수 있다. 여기서 normal block은 new 또는 malloc중 하나로 동적할당 했다는 얘기고 총 16바이트가 릭이 발생했단 얘기다. 우리는 여기서 81253과 0x03BB0AD0 두가지 정보를 가지고 브레이크 포인트를 걸 예정이다.


첫번째 방법

main함수의 최상단에 다음과 같은 구문을 삽입
_crtBreakAlloc = 81253;

그리고 디버깅을 해보면, 해당지점에 브레이크포인트가 걸린다. 콜스택으로 따라가면 어디에서 릭이 발생했는지 알 수 있다.


두번째 방법

일단 F11로 디버깅을 시작한다.
ALT+F9를 눌러서 중단점 창을 연 후, 새로만들기>새데이터중단점에서 주소부분에 저 주소(0x03BB0AD0)를 입력하고, 적당한 바이트(위의 경우는 16)를 기입하고 확인
F5로 계속 진행하여 그 부분을 찾아낸다.



 







 

2010. 4. 20. 03:14

ZeroMemory또는 memset시 유의사항


보통 데이터를 갖는 구조체들은 구조체에 값을 채우기전에 초기화작업을 많이 하고들 합니다. 보통 아래와 같은 구문을 주로 쓰는 편인데..
memset( &data, 0, sizeof( data ) );
또는
ZeroMemory( &data, sizeof( data ) );


하지만, 구조체에 STL이 포함되어있는 경우는 각별한 주의를 요합니다. 이를 테면..
struct Data
{
    string str;
    vector<int> nums;
};



실행중에는 별다른 이상이 없어보이지만, 디버깅을 하면, 메모리누수가 나는 것을 볼 수 있습니다.
많은 경우를 모두 테스트 해보지 않았지만, vector의 경우는 별다른 이상이 없었지만.. string의 경우는 메모리 누수가 발생합니다. str변수를 new를 통해 생성하지 않았음에도 말이죠. 사실 내부적으로도 동적 할당되구요. 차례대로 따라가다보시면 더 확실히 알 수 있습니다.

어쨌든 별생각없이 ZeroMemory한 결과였고, 실행중에 정상적으로 나오기 때문에 별다른 걸 못느꼈지만, 디버깅을 해보니 누수되었다고 나오더군요.



결론은 STL변수의 저장공간을 절대 0으로 초기화하지 말아야 합니다. 당연한 얘기일수도 있으나, 의외로 실수가 잦으니 항상 숙지하시기 바랍니다.