GDI+ 의 메모리 릭 디텍트 방법

음.. 오늘 GDI+ 에서 memory leak 이 발생할 경우 비주얼스튜디오가 전혀 감지를 못하는걸 보고 미친듯이 뷁뷁을 외쳐주다가 찾은자료.

http://www.codeproject.com/vcpp/gdiplus/gdiplush.asp

일단 읽어보니 GDI+ 의 경우 자체적인 메모리 할당 연산자를 사용하는데 이것이 Gdiplus.dll 내부에서 어찌어찌 쌓여서.. 비주얼 스튜디오에서는 감지를 못하는 상황인듯 하다.
위에서 사용한 방법은 특정 메크로가 정의 되어있지 않을때(!)는 GdiplusBase 객체를 자체적으로 다시 정의해서 내부의 메모리 할당 연산을 일반적인 new/delete (윈도우에서 가장 기본적으로 제공함으로써 비주얼스튜디오에서 감지가능한것)을 사용하게 하는것이다.

위의 URL에서 다운을 받으면 헤더 파일이 나오는데 그걸 Gdiplus.h 대신 인클루드 하고 사용하면 된다.

MFC에서 new 를 DEBUG_NEW로 재정의 하는 것과 비슷한… 거시기.

아래는 위의 URL의 소스를 기억용으로 한글로 주석 달아놓은것
아직 깔끔하게 적용하지 못해서 좀 찝찝하다.
예를 들어 메모리 릭이 났을 경우 소스파일의 라인을 출력해야 되는데 이건 그냥 저 헤더파일을 출력한다. 메크로로 잘 정의하면 될것 같긴 한데 느므느므 귀찮다.



GeSHi © 2004, Nigel McNie



  1. #ifndef _GDIPLUSH_H_INCLUDED_


  2. #define _GDIPLUSH_H_INCLUDED_


  3.  


  4. /// @file               AntGdiplusHelper.h


  5. /// @brief              GDI+ 메모리 연산자 재정의 헤더파일. 메모리 누수시 감지를 위함. 


  6. /// @warning    Gdiplus.h 대신 해당 파일을 인클루드 해야 함.


  7. /// @warning    Debug 에서는 GDIPLUS_USE_GDIPLUS_MEM 정의 하지 않음 -> Gdiplus 메모리 연산자를 사용하지 않고 릭 감지 가능


  8. /// @warning    Release 에서는 GDIPLUS_USE_GDIPLUS_MEM를 정의함 -> Gdiplus 메모리 연산자를 사용하지 않고 릭 감지 못함


  9.  


  10. //


  11. // GDI+ helper file v1.0


  12. // Written by Zoltan Csizmadia (zoltan_csizmadia@yahoo.com)


  13. //


  14.  


  15. // GDIPLUS_USE_GDIPLUS_MEM:


  16. // 위의 메크로가 정의 되어있을때 GDI+ 에서 제공하는 메모리 할당 함수를 사용한다.


  17. // 이 경우 _CrtXXXXX에 해당하는 메모리 디버깅용 함수가 일반적으로 작동하지 않는다.


  18. // (원래 GDI+는 _CrtXXXX 가 작동하지 못했다. 즉 해당 메크로를 설정하는게 기본설정.)


  19. //#define GDIPLUS_USE_GDIPLUS_MEM


  20.  


  21.  


  22. #ifdef _GDIPLUS_H


  23. #error Gdiplus.h is already included. You have to include this file instead.


  24. #endif


  25.  


  26.  


  27. #define _GDIPLUSBASE_H


  28.  


  29. namespace Gdiplus


  30. {


  31.     namespace DllExports


  32.     {


  33.         #include “GdiplusMem.h”


  34.     };


  35.  


  36.     class GdiplusBase


  37.     {


  38.     public:


  39. #ifdef _DEBUG


  40.         static void* __cdecl GdiplusAlloc( size_t nSize, LPCSTR szFileName, int nLine )


  41.         {


  42. #ifdef GDIPLUS_USE_GDIPLUS_MEM


  43.             UNREFERENCED_PARAMETER(szFileName);


  44.             UNREFERENCED_PARAMETER(nLine);


  45.             return DllExports::GdipAlloc(nSize);


  46. #else


  47.             return ::operator new( nSize, szFileName, nLine );


  48. #endif  // GDIPLUS_USE_GDIPLUS_MEM


  49.         }


  50.  


  51.         static void GdiplusFree( void* pVoid, LPCSTR szFileName, int nLine )


  52.         {


  53. #ifdef GDIPLUS_USE_GDIPLUS_MEM


  54.             UNREFERENCED_PARAMETER(szFileName);


  55.             UNREFERENCED_PARAMETER(nLine);


  56.             DllExports::GdipFree(pVoid);


  57. #else


  58.             ::operator delete( pVoid, szFileName, nLine );


  59. #endif  // GDIPLUS_USE_GDIPLUS_MEM


  60.         }


  61.        


  62.         void* (operator new)(size_t nSize)


  63.         {


  64.             return GdiplusAlloc( nSize, __FILE__, __LINE__ );


  65.         }


  66.         void* (operator new[])(size_t nSize)


  67.         {


  68.             return GdiplusAlloc( nSize, __FILE__, __LINE__ );


  69.         }


  70.         void * (operator new)(size_t nSize, LPCSTR lpszFileName, int nLine)


  71.         {


  72.             return GdiplusAlloc( nSize, lpszFileName, nLine );


  73.         }


  74.         void (operator delete)(void* pVoid)


  75.         {


  76.             GdiplusFree( pVoid, __FILE__, __LINE__ );


  77.         }


  78.         void (operator delete[])(void* pVoid)


  79.         {


  80.             GdiplusFree( pVoid, __FILE__, __LINE__ );


  81.         }


  82.         void operator delete(void* pVoid, LPCSTR lpszFileName, int nLine)


  83.         {


  84.             GdiplusFree( pVoid, lpszFileName, nLine);


  85.         }


  86. #else // _DEBUG


  87.  


  88.         static void* __cdecl GdiplusAlloc( size_t nSize )


  89.         {


  90. #ifdef GDIPLUS_USE_GDIPLUS_MEM


  91.             return DllExports::GdipAlloc(nSize);


  92. #else


  93.             return ::operator new(nSize);


  94. #endif  // GDIPLUS_USE_GDIPLUS_MEM


  95.         }


  96.  


  97.         static void GdiplusFree( void* pVoid )


  98.         {


  99. #ifdef GDIPLUS_USE_GDIPLUS_MEM


  100.             DllExports::GdipFree(pVoid);


  101. #else


  102.             ::operator delete( pVoid );


  103. #endif  // GDIPLUS_USE_GDIPLUS_MEM


  104.         }


  105.  


  106.         void* (operator new)(size_t nSize)


  107.         {


  108.             return GdiplusAlloc( nSize );


  109.         }


  110.         void* (operator new[])(size_t nSize)


  111.         {


  112.             return GdiplusAlloc( nSize );


  113.         }


  114.         void (operator delete)(void* pVoid)


  115.         {


  116.             GdiplusFree( pVoid );


  117.         }


  118.         void (operator delete[])(void* pVoid)


  119.         {


  120.             GdiplusFree( pVoid );


  121.         }


  122. #endif  // _DEBUG


  123.     };


  124. };


  125.  


  126. #include <Gdiplus.h>


  127.  


  128. #endif


  129.  

Parsed in 0.179 seconds

“GDI+ 의 메모리 릭 디텍트 방법”에 대한 2개의 댓글

  1. GDI+에서 그런식으로 메모리를 처리한 이유가 있을테니… 디버깅시가 아닐 때에는 원래 메모리 연산자를 써야하고…
    크아 이 설정은 요렇게 저 설정은 저렇게 하다가 에러나기 시작하면 초난감인데! ㅂ뤡ㄹ부레게뷁

  2. 저 위의 헤더파일 추가하고
    #define new DEBUG_NEW
    도 정의 해놓으니깐 걍 잘되내 -_-;
    릭난곳 소스코드랑 라인도 나오고.
    당췌 어떻게 변환하는건지 이해가 안가는데!

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다