VC6でのメモリリーク対策

VC6でのメモリリーク対策。http://msdn.microsoft.com/library/ja/jpdnvc60/htm/MemLeaks.asp?frame=true

検出のために以下の3行を追加すれば、メモリリークした場所が特定できると記述されている。

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

で、やってみた結果がこれ。

Detected memory leaks!
Dumping objects ->
Z:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {128} normal block at 0x004C1940, 209 bytes long.
 Data: <S   !       DIKE> 53 00 00 00 21 82 00 00 C1 00 00 00 44 49 4B 45 
Z:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {127} normal block at 0x004C1BC0, 12 bytes long.
 Data: <@ L         > 40 19 4C 00 D1 00 00 00 01 00 00 00 
Object dump complete.

crtdbg.h の552行目w見ると・・・

#ifdef _CRTDBG_MAP_ALLOC

inline void* __cdecl operator new(unsigned int s)
        { return ::operator new(s, _NORMAL_BLOCK, __FILE__, __LINE__); }

#endif  /* _CRTDBG_MAP_ALLOC */

見事にヘッダの中で__FILE__と__LINE__がプリプロで展開されてますねw

結論として、#define _CRTDBG_MAP_ALLOCは訳にたたない、と。けれども、先のリンクには有用な情報もあって次の方法を利用する。まずは以下のデバッグ情報の{127}{128}に注目する。

Detected memory leaks!
Dumping objects ->
{128} normal block at 0x004C1940, 209 bytes long.
 Data: <S   !       DIKE> 53 00 00 00 21 82 00 00 C1 00 00 00 44 49 4B 45 
{127} normal block at 0x004C1BC0, 12 bytes long.
 Data: <@ L         > 40 19 4C 00 D1 00 00 00 01 00 00 00 
Object dump complete.

これは、メモリ割り当て番号で127番目と128番目に割り当てられたメモリがリークしているという情報。この割り当て番号を使ってブレークする手順が以下。

  • プログラムの先頭でブレーク
  • ウォッチウィンドウに_crtBreakAllocを追加。
  • 値が-1になっている(たぶん)ので、127にする。
  • 実行

これで、127回目にメモリが確保された時にブレークするので、コールスタックを辿ればメモリリークしている箇所が特定できる。いや、知らんかったわ。マルチスレッドの場合は_crtBreakAllocのかわりに{,,msvcrtd.dll}_crtBreakAllocだそう。
ちなみに、crtdbg.hをインクルードしてmainの先頭に以下の行を追加してます。

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);