アプリ版:「スタンプのみでお礼する」機能のリリースについて

メモリリークについて教えてください。
最近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とかの解放はしているのですが、他にメモリリークをする原因ってあるのでしょうか?

A 回答 (6件)

>ただ、strcore.cppというクラスは作成していないのですが、エラーが出ます。



.cppって位だからソースでしょ(^^;;;
で、(118)が行番号。

MFCのソースはインストールしてますか?
VC++6.0SP6だと、該当行はCString::AllocBuffer()でした。


>newとかの解放はしているのですが、他にメモリリークをする原因ってあるのでしょうか?

ちゃんと解放していないとか。
こんなソースだとリークします。
CString pstr* = new CString[2];
delete pstr;


あとは、MFC等のフレームワークを使っているのであれば、その内部。

メモリリークとは、何度も確保されても解放されずに使用量が増えていくのがまずいのであって、該当個所では1度だけ確保して終了時まで保持しておくという使い方であれば、まずくはありません。(気持ち悪い気もしますが)

この回答への補足

ありがとうございます。

原因の個所がわかりました。

[ソース] 一部抜粋
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);

補足日時:2005/03/16 17:32
    • good
    • 0

ヘルプより:


>lpCommandLine
>実行するべきコマンドラインを保持している、NULL で終わる文字列へのポインタを指定します。
>システムはこのコマンドラインの最後に NULL を追加し、必要に応じて文字列を切り捨て、
>実際にどのファイルを使うのか指定します。

なんで、
>char *cl = new char[mstrCmdLine.GetLength() + 1];
足りてません。1ではなく2足してください。


>例 LPTSTR mstrCmdLine;
>mstrCmdLine = "cmd.exe";

これってキャストしないでコンパイル通りますか?

この回答への補足

たびたびご回答ありがとうございます。

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";
:
:
:
}
でやったらコンパイル通りました。
今考えると可笑しいですね。?(^^;?

補足日時:2005/03/16 23:11
    • good
    • 0

-----


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);
というコードを追加し、デバッグモードで実行してみましょう。
うまく行けば、メモリリークを起こしているオブジェクトを生成しているところで停止してくれます。
停止したら、そのオブジェクトが本当に解放されているのか確認してみて下さい。

ただしどちらの方法も起動するたびに{}の中の数字が変わるような状況では役に立ちません。ご注意下さい。

この回答への補足

ありがとうございます。
大変勉強になります。

まず、新規に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];
に戻ってきます。

何か設定していないことがあるのか??

補足日時:2005/03/17 10:40
    • good
    • 0

>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();
}

この回答への補足

いつもありがとうございます。

[ソース]
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系のメモリリークはなくなりました。
他のは調べていますが、よくわかりません。
問題ないようにも思えますが・・・

補足日時:2005/03/17 16:52
    • good
    • 0

>他のは調べていますが、よくわかりません。


>問題ないようにも思えますが・・・

ところで、_CrtDumpMemoryLeaks()どこで呼んでます?
    • good
    • 0
この回答へのお礼

ありがとうございます。

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

いろいろ最後までありがとうございました。

お礼日時:2005/03/18 09:31

_CrtDumpMemoryLeaks();を呼ぶのをもっと後にしてみて下さい。


例えば、CXxxAppクラスのデストラクタから呼んでみたら如何でしょうか。
    • good
    • 0
この回答へのお礼

ありがとうございます。

一番最後に付け加えてみたら、うまくいきました。

いろいろ勉強になりありがとうございました。

お礼日時:2005/03/18 09:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています