7

VC8からVC10にアップグレードしており、CDialogに関連していると思われるメモリリークが多数見つかりました。この最も簡単な例は、ボタンの数だけがあるCDialogを使用した次のコードで示されています。VC10ではこれはリークしますが、VC8ではリークしません。

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
  delete dialog;
}

メモリ使用量は増え続けており、約30個のボタンを使用したダイアログの例では数十Mbがリークしています。

上記は、ダイアログ処理コードをすべて削除したテスト例であることに注意してください。実際のコードでは、派生クラスがあり、PostNcDestroy()を使用しています。

奇妙なことに、次のコード例はいずれもVC8でもVC10でもリークしません。

CDialog* dialog = new CDialog;
for (int i = 0; i < 5000; ++i) {
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
}
delete dialog;

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  delete dialog;
}

ここで何が欠けていますか?

4

1 に答える 1

7

これは、MFCがハンドルマップを管理する方法に依存しているようです。

CWnd :: FromHandleから取得したCWndの有効期間はどれくらいですか?

アプリケーションがアイドル状態になるのに十分な時間待つと、メモリが元に戻ります。つまり、実際にはリークではありません。ただし、ご覧のとおり、Visual C ++ 2010は、OnIdle()でマップが整理されるまで、ますます多くのメモリを消費し続けますが、これはVisual C++2008では発生しないようです。

コードを含むアプリケーションをデバッグすると、VC9バージョンよりもVC10バージョンのHWND一時マップに多くのオブジェクトがあることがわかります。

ハンドルマップコード(winhand.cpp)は、2つのバージョン間で変更されていないようですが、MFCにはそれを使用するコードがたくさんあります。

とにかく、あなたが本当にこのようにあなたのプログラムを実行したいと仮定すると-私はあなたが何らかの自動モードで実行していると思いますか?-次に、適切な間隔でガベージコレクションを強制する必要があります。MSDNのこのエントリをご覧ください。

http://msdn.microsoft.com/en-us/library/xt4cxa4e(v=VS.100).aspx

CWinThread :: OnIdle()は実際にこれを呼び出して、物事を整理します。

AfxLockTempMaps();
AfxUnlockTempMaps(/*TRUE*/);
于 2011-08-19T09:41:23.190 に答える