ページ 11

メモリリーク!

Posted: 2011年8月31日(水) 15:26
by みるくる
こんにちは。

私の作成しているプログラムに、メモリリークが発生していると言われました。
_CrtDumpMemoryLeaks();を使用して確認してみると、
確かにメモリリークが起きていると表示が出ています。

_CrtDumpMemoryLeaks();を使って、1行、1行どこでリークが発生しているかを確認したところ、ダイアログを宣言しているところでリークが始まっていました。

CClsDlg dlg;

のような感じで宣言しているだけなのですが、何か誤りがあるのでしょうか?

また、メモリリークを無くすためには、1行、1行こうやって確認していくしかないのでしょうか?
よろしくお願いします。

ビジュアルスタジオ2005にてMFCを使ってプログラムを作成しています。

Re: メモリリーク!

Posted: 2011年8月31日(水) 15:40
by softya(ソフト屋)
MFCなら_CrtDumpMemoryLeaks();を呼ばなくてもデバッグビルドなら呼び出されるはずですので見当違いです。
あと、細かいポイントで_CrtDumpMemoryLeaks();を呼び出したらリークしているのはあたりまえです(確保されたメモリが解放されているはずがない)。なのでプログラムの最後に呼ぶのが正しいです。

「メモリリークを検出するには」
http://www.hiramine.com/programming/win ... yleak.html

MFCの場合は、こういう追跡方法があります。
「MFC におけるメモリ リークの検出」
http://msdn.microsoft.com/ja-jp/library ... s.80).aspx

DEBUG_NEW の働きでリークした場所は特定できるはずです。
「メモリリークのメモリ確保場所を特定するには」
http://www.hiramine.com/programming/win ... yleak.html

Re: メモリリーク!

Posted: 2011年8月31日(水) 16:21
by みるくる
>MFCなら_CrtDumpMemoryLeaks();を呼ばなくてもデバッグビルドなら呼び出されるはずですので見当違いです。
これは「出力」に特に何も表示されていなければ、メモリリークは起きていないということですか?
うまく動作しなかったプログラムの動きを見ようと、ログを出力するようにしたら、うまく動作するようになった場合、これはメモリリークなのでしょうか?
各プログラムソースの間にログ出力の処理を入れただけなので、全体の処理としては何も変わっていないはずなのに動くようになってしまったので、もう、わけがわからないのです。

すいません。メモリリークのデバッグなんて初めてなので、右も左もわからないのです。

プログラムの最後に呼び出したら、やはりメモリリークが起きているような出力がされました。

何か、取り留めの無い文章になってしまいましたが、よろしくお願いします。

Re: メモリリーク!

Posted: 2011年8月31日(水) 16:25
by softya(ソフト屋)
MFCのデバッグビルドなら何もしなくて良いです。と言うよりMFCのフレームワークの仕組み上_CrtDumpMemoryLeaks();を呼ばないでください。
そもそもメモリリークされているというのは誰が、どの手段で確認したのでしょうか?

Re: メモリリーク!

Posted: 2011年8月31日(水) 16:45
by softya(ソフト屋)
MFCでシンプルなダイアログを作ってリークさせてみました。

コード:

//コードを一部抜粋
BOOL CMFCtestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// "バージョン情報..." メニューをシステム メニューに追加します。

	// IDM_ABOUTBOX は、システム コマンドの範囲内になければなりません。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
	//  Framework は、この設定を自動的に行います。
	SetIcon(m_hIcon, TRUE);			// 大きいアイコンの設定
	SetIcon(m_hIcon, FALSE);		// 小さいアイコンの設定

	// TODO: 初期化をここに追加します。
	int *reek = new int;
	int *reek2 = (int*)malloc(sizeof(int));

	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
}
出力に表示されたリークのレポートです。

コード:

Dumping objects ->
{365} normal block at 0x0061F510, 4 bytes long.
 Data: <    > CD CD CD CD 
c:\users\softya\documents\visual studio 2008\projects\mfctest\mfctest\mfctestdlg.cpp(101) : {364} normal block at 0x00612F28, 4 bytes long.
 Data: <    > CD CD CD CD 
Object dump complete.
{365} normal block at 0x0061F510, 4 bytes long.
の方は行番号が不明ですが、mallocした方です。わかりづらいですね。C++ではもこう言う意味でもmallocは避けてください。
mfctestdlg.cpp(101) : {364} normal block at 0x00612F28, 4 bytes long.
はnewの方ですがnewを行った行番号を確認できます。

ちなみに_CrtDumpMemoryLeaks();を呼びだしてはいませんよ。

Re: メモリリーク!

Posted: 2011年8月31日(水) 17:28
by ISLe
みるくる さんが書きました:うまく動作しなかったプログラムの動きを見ようと、ログを出力するようにしたら、うまく動作するようになった場合、これはメモリリークなのでしょうか?
各プログラムソースの間にログ出力の処理を入れただけなので、全体の処理としては何も変わっていないはずなのに動くようになってしまったので、もう、わけがわからないのです。
そういうときはバッファオーバーランを疑ったほうが良いかもしれません。
配列の確保した要素数を超えた添字を指定してアクセスするといった、不正なメモリアクセスです。
メモリリークとは異なります。

デバッグにおいては、むしろ何も変わっていない状況を作る(バグ発症時の状況を再現する)ことが極めて難しいです。
すべてを疑ってください。