C++におけるメモリリークの点検と位置決め

2948 ワード

WindowsプラットフォームでのC++メモリリークメモリのチェックと位置付けについて簡単に説明します.「メモリの漏洩を最速で検出」を参照してください.
 
Windowsプラットフォームでは、ヘッダファイルで定義されている以下の関数を使用して実行できます.
_CrtDumpMemoryLeaks();
//   main    ,        

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
//   main    (             )

long _CrtSetBreakAlloc(long lBreakAlloc);
//                  

以下は_CrtDumpMemoryLeaks()の詳細コード.(Debugバージョンでのみ有効)
#include 


void main()  
{    
    int* pLeak = new int[10];

    pLeak = nullptr;

    _CrtDumpMemoryLeaks(); 
} 

これにより、現在のプログラムの実行が終了すると、Vistual StudioのOutputウィンドウに次の情報が出力されます.
Detected memory leaks!  Dumping objects ->  c:/work/test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.   Data: CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD   Object dump complete.
 
以上の情報は、メモリ漏洩が発生したことを示しているようですが、具体的なメモリ漏洩の位置を特定することは依然として難しいです.
 
以下は、改良されたバージョンです.
#define _CRTDBG_MAP_ALLOC
//    malloc free      DEBUG  ,              。

#include 

#ifdef _DEBUG   
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)   
#endif
//    new   ,       new  ,                 。

void main()  
{    
    int* pLeak = new int[10];

    pLeak = nullptr;

    _CrtDumpMemoryLeaks(); 
}

しかし、特定のメモリ漏洩点を見つけるのは難しい場合があります.
以上のメモリリークレポートには、52回目のメモリ割り当てで割り当てられたメモリが回収されていないことを示す奇妙な情報({52})があることに気づいた.
メソッドlong_CrtSetBreakAlloc(long lBreakAlloc)は、プログラムを指定されたメモリ割り当て操作(すなわち、52回目のメモリ割り当て)で停止させることができる.
#include 


void main()  
{
    _CrtSetBreakAlloc(52);

    int* pLeak = new int[10];

    pLeak = nullptr;

    _CrtDumpMemoryLeaks(); 
}

再びVSで上記のコードを実行すると、プログラムは指定された場所で停止してデバッグ状態になります.関数呼び出しスタックを表示することで、エラーのコード行とその時のプログラムの実行状態を正確に特定できます.
ここで、もう一つ注意したいのはC++のグローバル変数で、一部のグローバル変数の初期化はmainメソッドに入る前に発生します.この場合、上記の方法は依然として無効である.詳しくは次の例を参照してください.
struct MyCls
{
    string SubExprStr;
};


MyCls g_MyCls = {
    string("Hello world!")
};

 
上記コードのうち、g_MyClsオブジェクトインスタンスの初期化はmainメソッドに入る前に完了しました.この場合、条件ブレークポイントを設定することで完了できます.具体的には以下の通りです.
// file 'dbgheap.c'

extern "C" static void * __cdecl _heap_alloc_dbg_impl(
        size_t nSize,
        int nBlockUse,
        const char * szFileName,
        int nLine,
        int * errno_tmp
        )
{
        // ...

        /* lock the heap
         */
        _mlock(_HEAP_LOCK);
        __try {

            // ...

            /* break into debugger at specific memory allocation */
            if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
                _CrtDbgBreak();

次の行に条件ブレークポイントを設定し、変数lRequestが所定のメモリ割当て回数に等しい場合に実行を停止します.
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)

上記の方法は、本人の機器(Windows 7 VS 2010)でのテストに有効であり、他の状況ではしばらく検証されていない.