重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

環境:VC++6.0 MFC使用 ダイアログベースアプリケーション
使用PC:同一ソースをWin2000またはWinXPでリビルドして使用
です。

メインダイアログにメニューを実装し、あるメニュー項目を
選ぶと別のダイアログをDoModalで表示し、別のダイアログで「OK」を
押すとメインダイアログに処理が戻るようなソフトを作成しています。
別のダイアログは数種類あり、EDITボックスやコンボボックスなどを
配置しています。

ダイアログ切り替えの運用試験として、
あるダイアログを表示→閉じるを繰り返す試験を行っていると、
数時間でこのソフトが異常終了してしまいます。
(タイマ処理内で、現在日時分秒を出力しています)
「あるダイアログを表示」は、ソフトのタイマ処理で5秒おきにDoModalしています。
「閉じる」は、「OK」ボタンを押す別アプリを作成しています。
別アプリでは、「IsWindowVisible()の戻り値がTRUE」かつ
「FindWindowExを使用してlpszWindow(ウインドウ名)が「OK」」
のコントロールを探し出し、見つかればSendMessageなどで
「OK」ボタンを押す処理を代行させています。

何が原因で異常終了してしまうかを調べたいのですが、
具体的な良い方法はありませんでしょうか。

わかっている現象として、
1.タスクマネージャのプロセスタブで
このソフトのメモリ使用量を見ていると、
時間とともに少しずつ増加しています。

よろしくお願いいたします。

A 回答 (2件)

> CRTとは_CrtSetDbgFlag ... でしょうか?



御意。

> 異常の検出は無いようです。入れる場所が悪いのでしょうか。

悪いです。_CrtSetDbgFlagは起動直後など最初にやるものですので、
その位置でやっても恐らく結果が出てません。
最初に設定をしておいて、_CrtDumpMemoryLeaks等で結果を得ます。
# BoundsCheckerをお使いなら、近しい機能ともいえますが。

尚、デバッグ版実行時や上記設定時などはメモリがチェックの為に内部的に解放されず、
メモリが増え続けるように見えることがあります。
メモリ消費が増え続ける云々は、最低限リリース版で確認する必要があります。
# リリース版でもキャッシュのために解放されないものもありえますが。
また、staticなインスタンス内などで動的確保しても誤検出がありえます。

確証に至る情報はないのですが、何か漏らしてるとしたら、
DoModalで起動されるダイアログの中身の方じゃないですか?

再現コードがあるといいのですが、徐々に処理を削って公開できる
ものは作れませんか?(この過程で原因が分かることも多いので、
最小限の再現コードを作るのは王道ですが)

この回答への補足

MrBan様

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

>悪いです。_CrtSetDbgFlagは起動直後など最初にやるものですので、
>その位置でやっても恐らく結果が出てません。
>最初に設定をしておいて、_CrtDumpMemoryLeaks等で結果を得ます。

初めて使用したこともあり、勉強不足でした。
ご指摘ありがとうございます。

MSDNで調べてみましたが、コードの記述位置について教えていただけませんでしょうか。

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

は、
BOOL CxxxApp::InitInstance()
のあるファイルの
#include
の行の後に記述

2.
_CrtDumpMemoryLeaks
は、
BOOL CVisionSoftApp::InitInstance()
の一番最後に記述

3.
_CrtSetDbgFlag


BOOL CVisionSoftApp::InitInstance()
の一番最初に記述

でよいのでしょうか。




質問が増えてしまいますがすみません。
新たに新規プロジェクト(ダイアログベース)を作成し、上記の3つのコードのみを追加し
実行したところ、
「プロジェクト」メニュー→「設定」→「一般」タブ「Microsoft Foudation Class」で
「共有DLLでMFCを使用」にした場合、実行してすぐに「OK」を押してもリークが発生し、
「MFCのスタティックライブラリを使用」に設定した場合、実行してすぐに「OK」を押してもリークは
発生しませんでした。
これは、「共有DLLでMFCを使用」にした場合、DLLに問題がありリークが発生している
と考えてよいのでしょうか。



>メモリ消費が増え続ける云々は、最低限リリース版で確認する必要があります。
># リリース版でもキャッシュのために解放されないものもありえますが。

これは、「タスクマネージャ」の「メモリ使用量」の値に惑わされてはいけないということでしょうか。
メモリ消費が増加しても、延々と増加する場合は問題ですが、
起動後増加していても、ある地点で安定していれば問題ないということでしょうか。




>確証に至る情報はないのですが、何か漏らしてるとしたら、
>DoModalで起動されるダイアログの中身の方じゃないですか?
>再現コードがあるといいのですが、徐々に処理を削って公開できる
>ものは作れませんか?(この過程で原因が分かることも多いので、
>最小限の再現コードを作るのは王道ですが)

はい、メイン画面(起動後初期表示される画面)を表示したままであれば
「メモリ使用量」は増えませんが、DoModalでダイアログを表示すると
「メモリ使用量」が増えていくことがあります。
おそらく、DoModalで起動されるダイアログの方に問題があると思っています。
機能を削ったコードを用意しますので申し訳ありませんが、
少し時間をいただけませんでしょうか。

頼ってばかりで申し訳ありませんが、もう少しの間ご指導お願いいたします。

補足日時:2007/07/16 23:34
    • good
    • 0

症状からみて、メモリリーク(バグ)してる可能性もありそうです。


異常終了はメモリ確保失敗の結果、不正参照とかですかね…?
もしくは、タイミング問題のバグとか。

いずれにせよ、ちゃんとデバッグしてください。

VCならCRT(C Runtime)にメモリリークチェック機能がありますので、
多少は役に立つかもしれません。調べてみてください。

市販のメモリチェッカなども販売されてますが、今更VC6版があるかどうか…。

この回答への補足

チェックツールは、BoundsCheckerを使用していますが、
ソフト動作中は異常の検出は無いようです。

CRTとは
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
でしょうか?
各ダイアログのOnOKの最後に入れていますが、
異常の検出は無いようです。入れる場所が悪いのでしょうか。

「タイミング問題」については、なんともいえませんが、
void CVisionSoftDlg::OnTimer(UINT nIDEvent)
{
static long lDlgCount = 0;

switch( nIDEvent )
{
case ID_TIMER_1 :
KillTimer( ID_TIMER_1 );

switch( lDlgCount )
{
case 0 :
// ダイアログ1 DoModal()
break;

・・・

case 9 :
// ダイアログ10 DoModal()
break;

}
lDlgCount++;
if( 10 < lDlgCount )
{
lDlgCount = 0;
}

SetTimer( ID_TIMER_1, ID_TIMER_1_INTERVAL, NULL );
break;

default :
break;
}
CDialog::OnTimer(nIDEvent);
}
のようにして、前のダイアログの終了処理が終わる前に
次のダイアログが表示されないようにはしているつもりです。

私としては、
>1.タスクマネージャのプロセスタブで
>このソフトのメモリ使用量を見ていると、
>時間とともに少しずつ増加しています。
が気になっています。
上の現象=リークと考えてよいものでしょうか。

他に気にする点がありましたらご指摘お願いいたします。

補足日時:2007/07/15 14:02
    • good
    • 0

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