CodeGuru Forums -
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic Newsletters VB Forums Developer.com


Newest CodeGuru.com Articles:

  • Deploying Windows Server 2008 with System Center
  • Remote Desktop Protocol Performance Improvements in Windows Server 2008 R2 and Windows 7
  • The Microsoft Dynamics CRM Security Model
  • SQL Server Modeling Services with Microsoft Visual Studio 2010 Beta 2

  • Search CodeGuru:
     



    Go Back   CodeGuru Forums > CodeGuru Technical FAQs > CodeGuru Individual FAQs
    FAQ Members List Calendar Search Today's Posts Mark Forums Read

    CodeGuru Individual FAQs The indivdual FAQs for CodeGuru. See the specific Topic FAQ forums for index pages and links to these Frequently Asked/Answered Questions.

    Reply
     
    Thread Tools Search this Thread Display Modes
      #1    
    Old October 5th, 2004, 04:57 AM
    cilu's Avatar
    cilu cilu is offline
    Moderator/Reviewer/MS MVP
    Power Poster
     
    Join Date: Oct 2002
    Location: Timisoara, Romania
    Posts: 13,534
    cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+) cilu has a reputation beyond repute (3000+)
    Visual C++ Debugging: How to manage memory leaks?

    Q: What is a memory leak?

    A: The failure to properly deallocate memory that was previously allocated.



    Q: What are the consequences of memory leaks?

    A: Programs that leak large amounts of memory, or leak progressively, may display symptoms ranging from poor (and gradually decreasing) performance to running out of memory completely. Worse, a leaking program may use up so much memory that it causes another program to fail, leaving the user with no clue to where the problem truly lies. In addition, even harmless memory leaks may be symptomatic of other problems.



    Q: How can a memory leak appear?

    A: There are several causes:

    • Pointer goes out of scope:

      Code:
      void foo()
      {
        int *i = new int;
        *i = 44;
      }
      or

      Code:
      {
        char* str = new char[20];
        strcpy(str,"memory leak");
      }

    • "Lost" pointers

      Code:
      class Sample
      {
        int* val;
      
      public:
        Sample()
        {
          val = new int;
          *val = 44;
        }
      
        ~Sample()
        {
          delete val;
        }
      };
      
      void foo()
      {
        Sample* a = new Sample;
        Sample* b = new Sample;
        a = b;
      
        delete a; // actually deletes b
      
      //delete b; // already deleted
      }

    • Wrong usage of new/delete

      Code:
      double* d = new double[10];
      
      delete d; // delete d[0]; 
      	  // must use delete [] d;

    • Misplaced delete

      Code:
      int *i;
      while(someCondition)
      {
        i = new int;
        // some code
      }
      delete i;


    Q: How can I find if my program has memory leaks?

    A: When you run your program under the debugger, '_CrtDumpMemoryLeaks()' displays memory leak information in the output window. The memory leak information looks like this:

    Code:
    Detected memory leaks!
    Dumping objects ->
    D:\VisualC++\CodeGuru\MemoryLeak\MemoryLeak.cpp(67) : {60} 
    normal block at 0x00324818, 4 bytes long.
    Data: <,   > 2C 00 00 00 
    Object dump complete.
    If you do not use the '#define _CRTDBG_MAP_ALLOC' statement, defined in 'crtdbg.h', included in 'afx.h', which is by default included in your 'stdafx.h', the memory leak dump would look like this

    Code:
    Detected memory leaks!
    Dumping objects ->
    {60} normal block at 0x00324818, 4 bytes long.
    Data: <,   > 2C 00 00 00 
    Object dump complete.
    Without '_CRTDBG_MAP_ALLOC' defined, the display shows:
    • The memory allocation number (inside the curly braces).
    • The block type (normal, client, or CRT).
    • The memory location in hexadecimal form.
    • The size of the block in bytes.
    • The contents of the first 16 bytes (also in hexadecimal).
    With '_CRTDBG_MAP_ALLOC' defined, the display also shows you the file where the leaked memory was allocated. The number in parentheses following the filename (67, in this example) is the line number within the file.



    Q: What is the effect of using '_CRTDBG_MAP_ALLOC' on the C++ 'new' and 'delete' operators?

    A: When the '_CRTDBG_MAP_ALLOC' flag is defined in the debug version of an application, the base version of the heap functions are directly mapped to their debug versions. This flag is only available when the '_DEBUG' flag has been defined in the application.

    The debug versions of the C run-time library contain debug versions of the C++ 'new' and 'delete' operators. If your C++ code defines 'CRTDBG_MAP_ALLOC', all instances of new are mapped to the debug version, which records source file and line number information.

    If you want to use the '_CLIENT_BLOCK' allocation type, do not define 'CRTDBG_MAP_ALLOC'. Instead, you must call the Debug version of the 'new' operator directly or create macros that replace the 'new' operator in debug mode, as shown in the following example. The debug version of the 'delete' operator works with all block types and requires no changes in your program when you compile a release version.

    Code:
    // DbgNew.h
    // Defines global operator new to allocate from client blocks
    
    #ifdef _DEBUG
       #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
    #else
       #define DEBUG_CLIENTBLOCK
    #endif
    
    
    // MyApp.cpp
    // Compile options needed: /Zi /D_DEBUG /MLd or use a
    // Default Workspace for a Console Application to build a debug version
    
    #include <crtdbg.h>
    #include <dbgnew.h>
    
    #ifdef _DEBUG
    #define new DEBUG_CLIENTBLOCK
    #endif
    
    int main( )   
    {
       int* array = new int[10];
       _CrtMemDumpAllObjectsSince(NULL);
    
       return 0;
    }

    Q: Are there 'CRT' functions that report the state and content of the heap that can help me to detect memory leaks?

    A: In 'crtdbg.h' the following structure is defined:

    Code:
    typedef struct _CrtMemState
    {
            struct _CrtMemBlockHeader* pBlockHeader;// Pointer to the most recently allocated block
            unsigned long lCounts[_MAX_BLOCKS];	// A counter for each of the 5 types of block
            unsigned long lSizes[_MAX_BLOCKS];	// Total bytes allocated in each block type
            unsigned long lHighWaterCount;		// The most bytes allocated at a time up to now
            unsigned long lTotalCount;		// The total bytes allocated at present
    } _CrtMemState;
    This structure saves a pointer to the first (most recently allocated) block in the debug heap's linked list. Then, in two arrays, it records how many of each type of memory block ('_NORMAL_BLOCK', '_CLIENT_BLOCK', 'FREE_BLOCK' and so forth) are in the list and the number of bytes allocated in each type of block. Finally, it records the highest number of bytes allocated in the heap as a whole up to that point, and the number of bytes currently allocated.

    The following functions report the state and contents of the heap, and use the information to help detect memory leaks and other problems:
    • 'CrtMemCheckpoint' -> Saves a snapshot of the heap in a '_CrtMemState' structure supplied by the application.


    • '_CrtMemDifference' -> Compares two memory state structures, saves the difference between them in a third state structure, and returns 'TRUE' if the two states are different.


    • '_CrtMemDumpStatistics' -> Dumps a given '_CrtMemState' structure. The structure may contain a snapshot of the state of the debug heap at a given moment or the difference between two snapshots.

      Code:
      _CrtMemState s1, s2, s3;
      
      _CrtMemCheckpoint( &s1 );
      // memory allocations take place here
      _CrtMemCheckpoint( &s2 );
      
      if ( _CrtMemDifference( &s3, &s1, &s2) )
         _CrtMemDumpStatistics( &s3 );

    • '_CrtMemDumpAllObjectsSince' -> Dumps information about all objects allocated since a given snapshot was taken of the heap or from the start of execution. Every time it dumps a '_CLIENT_BLOCK' block, it calls a hook function supplied by the application, if one has been installed using '_CrtSetDumpClient'.


    • '_CrtDumpMemoryLeaks': Determines whether any memory leaks occurred since the start of program execution and, if so, dumps all allocated objects. Every time '_CrtDumpMemoryLeaks' dumps a '_CLIENT_BLOCK' block, it calls a hook function supplied by the application, if one has been installed using '_CrtSetDumpClient'.


    Q: How can I dump memory leak information?

    A: You can dump memory leak information by including the following statement in your program:

    Code:
    #include <iostream>
    
    #define _CRTDBG_MAP_ALLOC
    #include <crtdbg.h>
    
    int main()
    {
       int* array = new int[10];
       _CrtDumpMemoryLeaks();
       return 0;
    }

    Q: How MFC helps me to detect memory leaks?

    A: You can make use of:
    • Tracking Memory Allocations: 'DEBUG_NEW' macro can be used to locate memory leaks
    • Enabling Memory Diagnostics: enable diagnostic tracing and select specific memory diagnostic features with 'afxMemDF'
    • Taking Memory Snapshots: snapshots with 'CMemoryState'
    • Viewing Memory Statistics: 'CMemoryState:: Difference' and 'CMemoryState:: DumpStatistics'
    • Object Dumps: 'CMemoryState:: DumpAllObjectsSince'


    Q: Cay you give me an example?

    A: This example shows how to take snapshots of memory to help locate a memory leak. Notice that the memory-checking statements are bracketed by #ifdef _DEBUG / #endif blocks so that they are compiled only in Win32 Debug versions of your program.

    Code:
    #ifdef _DEBUG
       CMemoryState oldMemState, newMemState, diffMemState;
       oldMemState.Checkpoint();
    #endif
    
       // Do your memory allocations and deallocations.
       CSite* p = new CSite( "CodeGuru", "http://www.codeguru.com");
    
    #ifdef _DEBUG
       newMemState.Checkpoint();
       if( diffMemState.Difference( oldMemState, newMemState ) )
       {
          TRACE( "Memory leaked!\n" );
       }
    #endif

    Q: How can I avoid getting memory leaks?

    A: Make sure that:
    • you use correctly 'new'/'delete' and 'new[]'/'delete[]' (also 'malloc'/'free')
    • pointers don't go out of scope before memory is released
    • if you allocate memory in a loop, you release it in each iteration



    Last edited by Andreas Masur; July 25th, 2005 at 02:15 AM.
    Reply With Quote
    Reply

    Bookmarks
    Go Back   CodeGuru Forums > CodeGuru Technical FAQs > CodeGuru Individual FAQs


    Thread Tools Search this Thread
    Search this Thread:

    Advanced Search
    Display Modes

    Posting Rules
    You may not post new threads
    You may not post replies
    You may not post attachments
    You may not edit your posts

    BB code is On
    Smilies are On
    [IMG] code is On
    HTML code is On
    Forum Jump


    All times are GMT -5. The time now is 02:29 PM.



    Acceptable Use Policy


    The Network for Technology Professionals

    Search:

    About Internet.com

    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers


    Powered by vBulletin® Version 3.7.3
    Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.