728x90
반응형

Visual C++ 메모리 누수(momory leaking) 탐지 방안

  • 프로그램을 작성할 때 동적 메모리 할당을 적절히 해제하지 않으면 메모리 누수가 발생합니다.
  • Visual C++에서는 이러한 문제를 손쉽게 탐지할 수 있는 디버그 기능을 제공합니다.
  • 이번 글에서는 간단한 코드 예제와 함께 Visual C++의 메모리 누수 탐지 방법과 원인을 분석해보겠습니다.


1. 문제 코드 예제

  • cpp

      #define _CRTDBG_MAP_ALLOC
      #include <cstdlib>
      #include <crtdbg.h>
      
      #ifdef _DEBUG
      	#ifndef DBG_NEW
      		#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
      		#define new DBG_NEW
      	#endif
      #endif  // _DEBUG
      
      class Simple 
      {
      public:
      	Simple() { mIntPtr = new int(); }
      	~Simple() { delete mIntPtr; }
      
      	void setValue(int value) { *mIntPtr = value; }
      
      private:
      	int* mIntPtr;
      };
      
      void doSomething(Simple*& outSimplePtr)
      {
      	outSimplePtr = new Simple(); // [3] 버그! 기존 객체를 삭제하지 않았다.
      }
      
      int main()
      {
      	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
      
      	Simple* simplePtr = new Simple(); // [1] 첫 번째 객체 할당
      
      	doSomething(simplePtr); // [2] 기존 객체 포인터를 덮어씌움
      
      	delete simplePtr; // [4] 두 번째 객체만 해제함
      
      	return 0;
      }
    


2. 문제점 분석

  • 위 코드의 핵심 문제는 doSomething() 함수에서 기존 Simple 객체를 삭제하지 않고 새로운 객체로 포인터를 덮어씌우는 점입니다.

  • simplePtr이 원래 가리키던 첫 번째 Simple 객체는 delete 되지 않고 포인터만 새 객체로 바뀝니다.

  • 이로 인해 첫 번째 객체의 메모리가 해제되지 않고 메모리 누수가 발생합니다.



3. Visual C++의 메모리 누수 탐지 방법

  • Visual C++에서는 다음과 같은 방법으로 메모리 누수를 자동으로 확인할 수 있습니다.

  • (1) #define _CRTDBG_MAP_ALLOC<crtdbg.h>를 포함합니다.

  • (2) main() 함수 시작 시점에 다음 코드를 추가합니다:

    • cpp

        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
      
  • (3) 프로그램 종료 시점에 메모리 누수가 감지되면 콘솔 창에 다음과 같은 출력이 나타납니다:

    • console

      Detected memory leaks!
      Dumping objects ->
      {번호} normal block at 0x주소, 4 bytes long.
       Data: <....> 00 00 00 00
      Object dump complete.
      
  • (4) DBG_NEW 매크로를 활용하면 누수된 객체의 파일명과 라인 번호까지 확인할 수 있습니다:

    • cpp

        #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
        #define new DBG_NEW
      


4. 올바른 코드 수정 예시

  • 가장 간단한 해결 방법은 doSomething() 함수 안에서 기존 포인터를 삭제한 후 새 객체를 할당하는 것입니다:

  • cpp

      void doSomething(Simple*& outSimplePtr)
      {
          delete outSimplePtr; // 기존 객체 삭제
          outSimplePtr = new Simple();
      }
    

  • 또는 현대적인 C++ 스타일로 std::unique_ptr을 사용하면 자동으로 메모리 해제가 가능해집니다:

  • cpp

      #include <memory>
      
      void doSomething(std::unique_ptr<Simple>& outSimplePtr)
      {
          outSimplePtr = std::make_unique<Simple>();
      }
      
      int main()
      {
          _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
      
          std::unique_ptr<Simple> simplePtr = std::make_unique<Simple>();
          doSomething(simplePtr);
      
          return 0; // 자동으로 해제됨
      }
    


5. 정리

  • Visual C++에서 메모리 누수는 _CrtSetDbgFlag_CrtDumpMemoryLeaks 기능을 통해 쉽게 탐지할 수 있습니다.
  • 특히 DBG_NEW 매크로를 통해 어느 파일의 몇 번째 줄에서 메모리 누수가 발생했는지 추적할 수 있다는 점은 매우 강력한 디버깅 도구입니다.
  • 동적 할당을 사용한다면 항상 delete를 적절히 사용하거나 std::unique_ptr과 같은 스마트 포인터를 적극 활용하여 누수를 방지하는 습관이 중요합니다.



  • 도움이 되셨으면 하단의 ❤️ 공감 버튼 부탁 드립니다. 감사합니다! 😄

728x90
반응형

+ Recent posts