• ベストアンサー

メモリリークの件

メモリリークについて教えてください。 最近VC++を勉強中なのですが、メモリリークというものを知り、_CrtDumpMemoryLeaks()をしたところ、以下のコメントが出力されました。 [コメント] Detected memory leaks! Dumping objects -> strcore.cpp(118) : {71} normal block at 0x00344978, 20 bytes long. Data: < cmd.> 01 00 00 00 07 00 00 00 07 00 00 00 63 6D 64 2E {48} client block at 0x003428E8, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003428E8, 64 bytes long {43} client block at 0x00342720, subtype 0, 64 bytes long. a CDynLinkLibrary object at $00342720, 64 bytes long {41} client block at 0x003425D0, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003425D0, 64 bytes long Object dump complete. スレッド 0x584 終了、終了コード 0 (0x0)。 上記のコメントから、メモリリークを起こしていることはわかりました。ただ、strcore.cppというクラスは作成していないのですが、エラーが出ます。 多分他の関数から呼ばれているクラスだと思うため、クラス等をコメントアウトして調べたのですが、エラーがまだ出力されます。 (Data: < cmd.> 01 00 00 00 07 00 00 00 07 00 00 00 63 6D 64 2Eここは自作クラス上の問題だと思います。) newとかの解放はしているのですが、他にメモリリークをする原因ってあるのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.5

>他のは調べていますが、よくわかりません。 >問題ないようにも思えますが・・・ ところで、_CrtDumpMemoryLeaks()どこで呼んでます?

poposan
質問者

お礼

ありがとうございます。 一番最後に付け加えてみたら、うまくいきました。 使い方が悪かったのですね。 いろいろ最後までありがとうございました。

その他の回答 (5)

  • MASATO3
  • ベストアンサー率60% (27/45)
回答No.6

_CrtDumpMemoryLeaks();を呼ぶのをもっと後にしてみて下さい。 例えば、CXxxAppクラスのデストラクタから呼んでみたら如何でしょうか。

poposan
質問者

お礼

ありがとうございます。 一番最後に付け加えてみたら、うまくいきました。 いろいろ勉強になりありがとうございました。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.4

>PCか、vc++か、記述に問題があるのか・・・ 記述というか確認方法ですかね。 _CrtDumpMemoryLeaks()を呼ぶタイミングが早すぎます。ローカル変数のデストラクタが呼ばれていません。 中括弧で処理を囲って、その前後でメモリリーク調査の関数を呼んでください。 もしくは調査対象の処理を別関数にするか。 void CMy2Dlg::OnOK() { // TODO: この位置にその他の検証用のコードを追加してください _CrtSetBreakAlloc(71); { //追加 PROCESS_INFORMATION pro_id; STARTUPINFO str_inf; ::ZeroMemory(&str_inf, sizeof(str_inf)); str_inf.cb = sizeof(str_inf); str_inf.dwFlags = STARTF_USESHOWWINDOW; str_inf.wShowWindow = SW_SHOW; CString mstrCmdLine; mstrCmdLine = "cmd.exe"; char *cl = new char[mstrCmdLine.GetLength() + 2]; strcpy(cl,mstrCmdLine); CreateProcess(NULL,cl,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id); delete[] cl; CDialog::OnOK(); } //追加 _CrtDumpMemoryLeaks(); }

poposan
質問者

補足

いつもありがとうございます。 [ソース] void CMy2Dlg::OnOK() { _CrtSetBreakAlloc(71); { // TODO: この位置にその他の検証用のコードを追加してください。 PROCESS_INFORMATION pro_id; STARTUPINFO str_inf; ::ZeroMemory(&str_inf,sizeof(str_inf)); str_inf.cb = sizeof(str_inf); str_inf.dwFlags = STARTF_USESHOWWINDOW; str_inf.wShowWindow = SW_SHOW; CString mstrCmdLine; mstrCmdLine = "cmd.exe"; char *cl = new char[mstrCmdLine.GetLength() + 2]; strcpy(cl,mstrCmdLine); CreateProcess(NULL,cl,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id); delete[] cl; CloseHandle(pro_id.hProcess); CDialog::OnOK(); } _CrtDumpMemoryLeaks(); } 以上のように記述したら、以下のような結果になりました。 umping objects -> {48} client block at 0x003428E8, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003428E8, 64 bytes long {43} client block at 0x00342720, subtype 0, 64 bytes long. a CDynLinkLibrary object at $00342720, 64 bytes long {41} client block at 0x003425D0, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003425D0, 64 bytes long Object dump complete. スレッド 0x790 終了、終了コード 0 (0x0)。 プログラム 'D:\work\1.docomo\作業\20050114 ファイルコピー\test\2\Debug\2.exe' はコード 0 (0x0) で終了しました。 一様CString系のメモリリークはなくなりました。 他のは調べていますが、よくわかりません。 問題ないようにも思えますが・・・

  • MASATO3
  • ベストアンサー率60% (27/45)
回答No.3

----- PROCESS_INFORMATION pro_id; STARTUPINFO str_inf; ::ZeroMemory(&str_inf, sizeof(str_inf)); str_inf.cb = sizeof(str_inf); str_inf.dwFlags = STARTF_USESHOWWINDOW; str_inf.wShowWindow = SW_SHOW; CString mstrCmdLine; mstrCmdLine = "cmd.exe"; char *cl = new char[mstrCmdLine.GetLength() + 2]; strcpy(cl,mstrCmdLine); CreateProcess(NULL,cl,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id); delete[] cl; ----- というコードを実行してみましたが、メモリリークは発生しませんでした。 ですので、原因はまだ明かされていないコードのどこかにあるのではないかと思います。 _CrtDumpMemoryLeaksにおいてメモリリークが検出された場合、一番最後に表示されたメモリリークに問題がある場合が多いです。 下から順番に解決していきましょう。 {41} client block at 0x003425D0, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003425D0, 64 bytes long 最初に解析するのはこれです。 このメモリリークの原因はもう解決しましたか? ●このメモリリークの原因探しに難航している場合 プログラムの先頭の方に _CrtSetBreakAlloc(41); というコードを追加し、デバッグモードで実行してみましょう。 うまく行けば、メモリリークを起こしているオブジェクトを生成しているところで停止してくれます。 停止したら、そのオブジェクトが本当に解放されているのか確認してみて下さい。 ●残りはもうstrcore.cppで発生しているメモリリークだけの場合 strcore.cpp(118) : {71} normal block at 0x00344978, 20 bytes long. Data: < cmd.> 01 00 00 00 07 00 00 00 07 00 00 00 63 6D 64 2E となっていますので、 プログラムの先頭の方に _CrtSetBreakAlloc(71); というコードを追加し、デバッグモードで実行してみましょう。 うまく行けば、メモリリークを起こしているオブジェクトを生成しているところで停止してくれます。 停止したら、そのオブジェクトが本当に解放されているのか確認してみて下さい。 ただしどちらの方法も起動するたびに{}の中の数字が変わるような状況では役に立ちません。ご注意下さい。

poposan
質問者

補足

ありがとうございます。 大変勉強になります。 まず、新規にVC6++を立ち上げ(MFC(exe)→ダイアログ)、以下のソースを入力したところ同じメモリリークになりました。(提供されたソースをコピーしました) [ソース] void CMy2Dlg::OnOK() { // TODO: この位置にその他の検証用のコードを追加してください _CrtSetBreakAlloc(71); PROCESS_INFORMATION pro_id; STARTUPINFO str_inf; ::ZeroMemory(&str_inf, sizeof(str_inf)); str_inf.cb = sizeof(str_inf); str_inf.dwFlags = STARTF_USESHOWWINDOW; str_inf.wShowWindow = SW_SHOW; CString mstrCmdLine; mstrCmdLine = "cmd.exe"; char *cl = new char[mstrCmdLine.GetLength() + 2]; strcpy(cl,mstrCmdLine); CreateProcess(NULL,cl,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id); delete[] cl; CDialog::OnOK(); _CrtDumpMemoryLeaks(); } ですが、 Detected memory leaks! Dumping objects -> strcore.cpp(118) : {71} normal block at 0x00344908, 20 bytes long. Data: < cmd.> 01 00 00 00 07 00 00 00 07 00 00 00 63 6D 64 2E {48} client block at 0x003428E8, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003428E8, 64 bytes long {43} client block at 0x00342720, subtype 0, 64 bytes long. a CDynLinkLibrary object at $00342720, 64 bytes long {41} client block at 0x003425D0, subtype 0, 64 bytes long. a CDynLinkLibrary object at $003425D0, 64 bytes long Object dump complete. スレッド 0x6C4 終了、終了コード 0 (0x0)。 の同じ結果が返ってきます。 PCか、vc++か、記述に問題があるのか・・・ 因みに、教えていただきました_CrtSetBreakAllocですが41、43、48でブレークはしませんでした。 71でブレークし見ると、 --------------------------- /* break into debugger at specific memory allocation */ if (lRequest == _crtBreakAlloc)  _CrtDbgBreak(); < ---- ここでとまっている。 --------------------------- そのままF10(Nextコンパイル)で見ていくと、 char *cl = new char[mstrCmdLine.GetLength() + 2]; に戻ってきます。 何か設定していないことがあるのか??

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

ヘルプより: >lpCommandLine >実行するべきコマンドラインを保持している、NULL で終わる文字列へのポインタを指定します。 >システムはこのコマンドラインの最後に NULL を追加し、必要に応じて文字列を切り捨て、 >実際にどのファイルを使うのか指定します。 なんで、 >char *cl = new char[mstrCmdLine.GetLength() + 1]; 足りてません。1ではなく2足してください。 >例 LPTSTR mstrCmdLine; >mstrCmdLine = "cmd.exe"; これってキャストしないでコンパイル通りますか?

poposan
質問者

補足

たびたびご回答ありがとうございます。 OS windows2000 visual c++ 6.0 を使用しています。 ■1 >char *cl = new char[mstrCmdLine.GetLength() + 2]; にしましたが、以前と変わらずエラーが出ました。 もっと調べないとだめですね(^^; 納得いかないですね。 ■2 >例 LPTSTR mstrCmdLine; >mstrCmdLine = "cmd.exe"; >これってキャストしないでコンパイル通りますか? class xxx : CObject private: LPTSTR mstrCmdLine; : : } int xxx::xxxx(){ mstrCmdLine = "cmd.exe"; : : : } でやったらコンパイル通りました。 今考えると可笑しいですね。?(^^;?

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

>ただ、strcore.cppというクラスは作成していないのですが、エラーが出ます。 .cppって位だからソースでしょ(^^;;; で、(118)が行番号。 MFCのソースはインストールしてますか? VC++6.0SP6だと、該当行はCString::AllocBuffer()でした。 >newとかの解放はしているのですが、他にメモリリークをする原因ってあるのでしょうか? ちゃんと解放していないとか。 こんなソースだとリークします。 CString pstr* = new CString[2]; delete pstr; あとは、MFC等のフレームワークを使っているのであれば、その内部。 メモリリークとは、何度も確保されても解放されずに使用量が増えていくのがまずいのであって、該当個所では1度だけ確保して終了時まで保持しておくという使い方であれば、まずくはありません。(気持ち悪い気もしますが)

poposan
質問者

補足

ありがとうございます。 原因の個所がわかりました。 [ソース] 一部抜粋 CString mstrCmdLine; mstrCmdLine = "cmd.exe"; char *cl = new char[mstrCmdLine.GetLength() + 1]; strcpy(cl,mstrCmdLine); nResult = CreateProcess(NULL,cl,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id); delete[] cl; CStringからLPTSTR型に変換をすると、CreateProcessでエラーが発生します。(cl) 直接clの部分を"cmd.exe"に直接記述するとメモリリークは起こさないみたいなので、char* への変換が間違っているのですか? だとするとCStringからchar*への変換は良くないのでしょうか? 直接変数を LPTSTR型で領域を確保したほうがよろしいのですか? 例 LPTSTR mstrCmdLine; mstrCmdLine = "cmd.exe"; nResult = CreateProcess(NULL,mstrCmdLine,NULL,NULL,FALSE,0,NULL,NULL,&str_inf,&pro_id);

関連するQ&A