CRT ライブラリを使用したメモリ リークの検出Find memory leaks with the CRT library

メモリ リークは、C/C++ アプリケーションで最も微妙なと検出が難しいバグです。Memory leaks are among the most subtle and hard-to-detect bugs in C/C++ apps. 結果が正しく割り当てられていたメモリの割り当てを解除する障害からのメモリ リークします。Memory leaks result from the failure to correctly deallocate memory that was previously allocated. 少量のメモリ リークは最初は、認識されない可能性がありますが、時間の経過と共にパフォーマンスの低下からクラッシュ、アプリのメモリが不足している場合に至るまでの現象が発生できます。A small memory leak might not be noticed at first, but over time can cause symptoms ranging from poor performance to crashing when the app runs out of memory. 使用可能なメモリを使用して他のアプリがクラッシュを引き起こす可能性のあるリークしているアプリは、混乱したりするアプリを作成します。A leaking app that uses up all available memory can cause other apps to crash, creating confusion as to which app is responsible. さらに無害なメモリ リークには、他の問題を修正する必要がありますを可能性があります。Even harmless memory leaks might indicate other problems that should be corrected.

Visual StudioVisual Studioデバッガーと C ランタイム ライブラリ (CRT) が検出して、メモリ リークを特定できます。The Visual StudioVisual Studio debugger and C Run-time Library (CRT) can help you detect and identify memory leaks.

メモリ リークの検出を有効にします。Enable memory leak detection

メモリ リーク、C と C++ デバッガーと C ランタイム ライブラリ (CRT) を検出するための主要ツールはデバッグ ヒープ関数です。The primary tools for detecting memory leaks are the C/C++ debugger and the C Run-time Library (CRT) debug heap functions.

すべてのデバッグ ヒープ関数を有効にするには、次の順序で、C++ プログラムで、次のステートメントを含めます。To enable all the debug heap functions, include the following statements in your C++ program, in the following order:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define ステートメントにより、CRT ヒープ関数の基本バージョンがデバッグ バージョンに対応付けられます。The #define statement maps a base version of the CRT heap functions to the corresponding debug version. 省略すると、#defineステートメントでは、メモリ リーク ダンプがなります情報します。If you leave out the #define statement, the memory leak dump will be less detailed.

含むcrtdbg.hマップ、mallocfree関数のデバッグ バージョンを_malloc_dbg_free_dbgメモリを追跡します。割り当てと解放します。Including crtdbg.h maps the malloc and free functions to their debug versions, _malloc_dbg and _free_dbg, which track memory allocation and deallocation. この対応付けは、 _DEBUGが定義されているデバッグ ビルドでだけ行われます。This mapping occurs only in debug builds, which have _DEBUG. リリース ビルドでは、通常の malloc 関数と free 関数が使用されます。Release builds use the ordinary malloc and free functions.

配置への呼び出しの前のステートメントを使用して、デバッグ ヒープ関数を有効にしたら、 _CrtDumpMemoryLeaksアプリが終了するときに、メモリ リーク レポートを表示するアプリを終了時点より前にします。After you've enabled the debug heap functions by using the preceding statements, place a call to _CrtDumpMemoryLeaks before an app exit point to display a memory-leak report when the app exits.

_CrtDumpMemoryLeaks();

手動で配置する必要がありますしない場合は、アプリは、いくつか終了しますがある、_CrtDumpMemoryLeaksですべての終了ポイント。If your app has several exits, you don't need to manually place _CrtDumpMemoryLeaks at every exit point. 自動呼び出しが発生する_CrtDumpMemoryLeaks各終了時点への呼び出しを配置_CrtSetDbgFlagビット フィールドを次に示しますを使用してアプリの開始時。To cause an automatic call to _CrtDumpMemoryLeaks at each exit point, place a call to _CrtSetDbgFlag at the beginning of your app with the bit fields shown here:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

既定では、 _CrtDumpMemoryLeaks は、メモリ リーク レポートを [出力] ウィンドウの デバッグ ウィンドウに出力します。By default, _CrtDumpMemoryLeaks outputs the memory-leak report to the Debug pane of the Output window. ライブラリを使用すると、情報の出力場所が別の場所に変更されることがあります。If you use a library, the library might reset the output to another location.

使用することができます_CrtSetReportModeに別の場所にレポートをリダイレクトしたり戻したりする、出力次に示すようにウィンドウ。You can use _CrtSetReportMode to redirect the report to another location, or back to the Output window as shown here:

_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

メモリ リーク レポートを解釈します。Interpret the memory-leak report

アプリが定義されていない場合_CRTDBG_MAP_ALLOC_CrtDumpMemoryLeaks次のようなメモリ リーク レポートが表示されます。If your app doesn't define _CRTDBG_MAP_ALLOC, _CrtDumpMemoryLeaks displays a memory-leak report that looks like:

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

アプリが定義されている場合_CRTDBG_MAP_ALLOC、次のように、メモリ リーク レポート。If your app defines _CRTDBG_MAP_ALLOC, the memory-leak report looks like:

Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\leaktest\leaktest.cpp(20) : {18}
normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

2 番目のレポートには、リークしたメモリが割り当てられている最初のファイル名と行の番号が表示されます。The second report shows the filename and line number where the leaked memory is first allocated.

かどうかを定義する_CRTDBG_MAP_ALLOC、メモリ リーク レポートが表示されます。Whether or not you define _CRTDBG_MAP_ALLOC, the memory-leak report displays:

  • これはメモリ割り当て番号18の例The memory allocation number, which is 18 in the example
  • ブロックの型、normalの例です。The block type, normal in the example.
  • 16 進数のメモリの場所、0x00780E80の例です。The hexadecimal memory location, 0x00780E80 in the example.
  • ブロックのサイズ64 bytesの例です。The size of the block, 64 bytes in the example.
  • ブロックのデータの最初の 16 バイト (16 進形式)The first 16 bytes of data in the block, in hexadecimal form.

メモリ ブロックの型は通常クライアント、またはCRTします。Memory block types are normal, client, or CRT. normal ブロック は、プログラムによって割り当てられる通常のメモリです。A normal block is ordinary memory allocated by your program. client ブロック は、デストラクターを必要とするオブジェクト用に、MFC プログラムが使用する特殊なメモリ ブロックです。A client block is a special type of memory block used by MFC programs for objects that require a destructor. MFC の new 演算子は、作成されるオブジェクトに応じて、normal ブロックまたは client ブロックを作成します。The MFC new operator creates either a normal block or a client block, as appropriate for the object being created.

CRT ブロック は、CRT ライブラリが独自に使用するために割り当てるメモリ ブロックです。A CRT block is allocated by the CRT library for its own use. CRT ブロックは、CRT ライブラリの重大な問題がある場合を除き、メモリ リーク レポートに表示されませんので、CRT ライブラリは、これらのブロックの割り当て解除を処理します。The CRT library handles the deallocation for these blocks, so CRT blocks won't appear in the memory-leak report unless there are serious problems with the CRT library.

これ以外に、メモリ リーク レポートに表示されないメモリ ブロックが 2 種類あります。There are two other types of memory blocks that never appear in memory-leak reports. A空きブロックメモリがリリースされている定義でリークされていないためです。A free block is memory that has been released, so by definition isn't leaked. ブロックを無視するは、メモリ リーク レポートから除外する明示的にマークされているメモリです。An ignore block is memory that you've explicitly marked to exclude from the memory-leak report.

上記の方法は、標準 CRT を使用して割り当てられたメモリのメモリ リークを特定malloc関数。The preceding techniques identify memory leaks for memory allocated using the standard CRT malloc function. プログラムが、C++ を使用してメモリを割り当てる場合new演算子、ただし、可能性がありますのみが表示されたファイル名および行番号、operator new呼び出し_malloc_dbgメモリ リーク レポートにします。If your program allocates memory using the C++ new operator, however, you may only see the filename and line number where operator new calls _malloc_dbg in the memory-leak report. さらに便利なメモリ リーク レポートを作成するには、割り当てを行った行を報告するには、次のようなマクロを記述できます。To create a more useful memory-leak report, you can write a macro like the following to report the line that made the allocation:

#ifdef _DEBUG
    #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
    // Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
    // allocations to be of _CLIENT_BLOCK type
#else
    #define DBG_NEW new
#endif

置き換えることができますので、new演算子を使用して、DBG_NEWコードでマクロ。Now you can replace the new operator by using the DBG_NEW macro in your code. デバッグ ビルドでDBG_NEWグローバルのオーバー ロードを使用してoperator newブロックの型、ファイル、および行番号の追加のパラメーターを受け取る。In debug builds, DBG_NEW uses an overload of global operator new that takes additional parameters for the block type, file, and line number. オーバー ロードnew呼び出し_malloc_dbg余分な情報を記録します。The overload of new calls _malloc_dbg to record the extra information. メモリ リーク レポートには、リークしたオブジェクトが割り当てられた、ファイル名と行の番号が表示されます。The memory-leak reports show the filename and line number where the leaked objects were allocated. リリース ビルドも使用して、既定newします。Release builds still use the default new. 次の手法の例に示します。Here's an example of the technique:

// debug_new.cpp
// compile by using: cl /EHsc /W4 /D_DEBUG /MDd debug_new.cpp
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>

#ifdef _DEBUG
    #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
    // Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
    // allocations to be of _CLIENT_BLOCK type
#else
    #define DBG_NEW new
#endif

struct Pod {
    int x;
};

void main() {
    Pod* pPod = DBG_NEW Pod;
    pPod = DBG_NEW Pod; // Oops, leaked the original pPod!
    delete pPod;

    _CrtDumpMemoryLeaks();
}

Visual Studio でこのコードを実行するときにデバッガーへの呼び出し_CrtDumpMemoryLeaksでレポートを生成、出力次のようなウィンドウ。When you run this code in the Visual Studio debugger, the call to _CrtDumpMemoryLeaks generates a report in the Output window that looks similar to:

Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\debug_new\debug_new.cpp(20) : {75}
 normal block at 0x0098B8C8, 4 bytes long.
 Data: <    > CD CD CD CD
Object dump complete.

これは、リークした割り当ての 20 行目がレポートを出力debug_new.cppします。This output reports that the leaked allocation was on line 20 of debug_new.cpp.

Note

という名前のプリプロセッサ マクロを作成するをお勧めしませんnew、またはその他の言語のキーワード。We don't recommend you create a preprocessor macro named new, or any other language keyword.

メモリ割り当て番号にブレークポイントを設定します。Set breakpoints on a memory allocation number

メモリ割り当て番号は、リークしているメモリ ブロックがいつ割り当てられたかを示します。The memory allocation number tells you when a leaked memory block was allocated. 18 のメモリ割り当て番号を持つブロックでは、アプリの実行中に割り当てられたメモリの 18 のブロックなどができます。A block with a memory allocation number of 18, for example, is the 18th block of memory allocated during the run of the app. CRT レポートでは、CRT ライブラリと MFC などの他のライブラリでの割り当てなど、実行時にメモリ ブロックのすべての割り当てをカウントします。The CRT report counts all memory-block allocations during the run, including allocations by the CRT library and other libraries such as MFC. そのため、メモリ割り当てブロック番号 18 18 に、コードによって割り当てられたメモリ ブロック可能性はありません。Therefore, memory allocation block number 18 probably isn't the 18th memory block allocated by your code.

この割り当て番号を使用して、メモリの割り当てにブレークポイントを設定できます。You can use the allocation number to set a breakpoint on the memory allocation.

ウォッチ ウィンドウを使用してメモリ割り当てブレークポイントを設定するにはTo set a memory-allocation breakpoint using the Watch window:

  1. アプリの冒頭にあるブレークポイントを設定し、デバッグを開始します。Set a breakpoint near the start of your app, and start debugging.

  2. アプリがブレークポイントで一時停止したときに開く、ウォッチウィンドウを選択してデバッグ > Windows > ウォッチ 1(または2 を見る3 を見る、または4 を見る)。When the app pauses at the breakpoint, open a Watch window by selecting Debug > Windows > Watch 1 (or Watch 2, Watch 3, or Watch 4).

  3. ウォッチウィンドウで、「_crtBreakAllocで、名前列。In the Watch window, type _crtBreakAlloc in the Name column.

    マルチ スレッド DLL バージョンの CRT ライブラリ (/MD オプション) を使用している場合は、コンテキスト演算子を追加します。 {,,ucrtbased.dll}_crtBreakAllocIf you're using the multithreaded DLL version of the CRT library (the /MD option), add the context operator: {,,ucrtbased.dll}_crtBreakAlloc

  4. Enter キーを押します。Press Enter.

    デバッガーによって呼び出しが評価され、その結果が [値] 列に表示されます。The debugger evaluates the call and places the result in the Value column. メモリ割り当てにまだブレークポイントが設定されていない場合、この値は -1 になります。This value will be -1 if you have not set any breakpoints on memory allocations.

  5. 列、値をデバッガーが中断するメモリ割り当ての割り当て番号に置き換えます。In the Value column, replace the value with the allocation number of the memory allocation where you want the debugger to break.

メモリ割り当て番号にブレークポイントを設定した後は、デバッグを続行します。After you set a breakpoint on a memory-allocation number, continue to debug. メモリ割り当て番号が変更されないため、同じ条件下で実行してください。Make sure to run under the same conditions, so the memory-allocation number doesn't change. 指定されたメモリの割り当てでプログラムが停止したらを使用して、呼び出し履歴ウィンドウとメモリが割り当てられた条件を確認するには、その他のデバッガー ウィンドウ。When your program breaks at the specified memory allocation, use the Call Stack window and other debugger windows to determine the conditions under which the memory was allocated. 次に、オブジェクトの動作を確認する実行を続行し、正常に解放されていない理由ことを確認します。Then, you can continue execution to observe what happens to the object and determine why it isn't correctly deallocated.

オブジェクトにデータ ブレークポイントを設定する方法も役に立つことがあります。Setting a data breakpoint on the object might also be helpful. 詳細については、「ブレークポイントの使用」を参照してください。For more information, see Using breakpoints.

さらに、コード内でメモリ割り当てブレークポイントを設定することもできます。You can also set memory-allocation breakpoints in code. 次のように設定できます。You can set:

_crtBreakAlloc = 18;

またはor:

_CrtSetBreakAlloc(18);

メモリの状態を比較します。Compare memory states

メモリ リークの位置を特定するためのもう 1 つの方法では、ある時点におけるアプリケーションのメモリ状態のスナップショットを取得します。Another technique for locating memory leaks involves taking snapshots of the application's memory state at key points. アプリケーションで特定の時点のメモリ状態のスナップショットを実行するには、作成、_CrtMemState構造体に渡すと、_CrtMemCheckpoint関数。To take a snapshot of the memory state at a given point in your application, create a _CrtMemState structure and pass it to the _CrtMemCheckpoint function.

_CrtMemState s1;
_CrtMemCheckpoint( &s1 );

_CrtMemCheckpoint関数は、現在のメモリ状態のスナップショットを構造に格納します。The _CrtMemCheckpoint function fills in the structure with a snapshot of the current memory state.

内容を出力する、_CrtMemState構造体、構造体を渡す、_ CrtMemDumpStatistics関数。To output the contents of a _CrtMemState structure, pass the structure to the _ CrtMemDumpStatistics function:

_CrtMemDumpStatistics( &s1 );

_ CrtMemDumpStatistics 次のようなメモリの状態のダンプが出力されます。_ CrtMemDumpStatistics outputs a dump of memory state that looks like:

0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.

コード内のセクションでメモリ リークが発生したかどうかを調べるには、そのセクションの前後のメモリ状態のスナップショットを取得した後、 _ CrtMemDifference を使用して 2 つのメモリ状態を比較します。To determine whether a memory leak has occurred in a section of code, you can take snapshots of the memory state before and after the section, and then use _ CrtMemDifference to compare the two states:

_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 );

if ( _CrtMemDifference( &s3, &s1, &s2) )
   _CrtMemDumpStatistics( &s3 );

_CrtMemDifference メモリ状態を比較s1s2で結果を返します (s3) 間の差はs1s2します。_CrtMemDifference compares the memory states s1 and s2 and returns a result in (s3) that is the difference between s1 and s2.

配置することでメモリ リークを検索するための 1 つの方法は、まず_CrtMemCheckpoint先頭と末尾を使用して、アプリの呼び出し_CrtMemDifference結果を比較します。One technique for finding memory leaks begins by placing _CrtMemCheckpoint calls at the beginning and end of your app, then using _CrtMemDifference to compare the results. 場合_CrtMemDifferenceさらに追加することができます、メモリ リークを示しています_CrtMemCheckpoint呼び出しまで、リークの原因を分離している場合、バイナリ検索を使用してプログラムを分割します。If _CrtMemDifference shows a memory leak, you can add more _CrtMemCheckpoint calls to divide your program using a binary search, until you've isolated the source of the leak.

誤検知False positives

_CrtDumpMemoryLeaks ライブラリは、CRT ブロックまたはクライアントのブロックではなく通常のブロックとして内部の割り当てをマークした場合、メモリ リークの兆候が false を指定できます。_CrtDumpMemoryLeaks can give false indications of memory leaks if a library marks internal allocations as normal blocks instead of CRT blocks or client blocks. その場合、 _CrtDumpMemoryLeaks では、ユーザー割り当てとライブラリの内部的な割り当てを区別することができません。In that case, _CrtDumpMemoryLeaks is unable to tell the difference between user allocations and internal library allocations. ライブラリ割り当てのグローバル デストラクターが、 _CrtDumpMemoryLeaksの呼び出しポイント後に実行される場合、すべての内部ライブラリ割り当てがメモリ リークとして報告されます。If the global destructors for the library allocations run after the point where you call _CrtDumpMemoryLeaks, every internal library allocation is reported as a memory leak. 標準テンプレート ライブラリを Visual Studio .NET が発生する可能性がありますよりも前のバージョン_CrtDumpMemoryLeaksこのような誤検知を報告します。Versions of the Standard Template Library earlier than Visual Studio .NET may cause _CrtDumpMemoryLeaks to report such false positives.

関連項目See also