5

私は現在、マルチスレッドアプリケーションをデバッグしています。このアプリケーションは、一部の関数が約2000回呼び出されるまでエラーなしで実行されます。その後、アプリケーションは応答を停止します。これは、メモリ不足エラーで失敗した_beginthreadexまで追跡できます。

ProcessExplorerでアプリケーションを調べると、リークされたスレッドハンドルの数が増え、エラーが発生するまで仮想メモリが増えていることがわかります。プライベートバイトは低いままです。リークされたスレッドはCoInitializeも呼び出し、CoUninitializeを呼び出すことはありません。

私が知りたいのは:

  • 仮想メモリは何を表していますか?
  • 仮想メモリはリークされたスレッドハンドルに関連していますか?
  • COMまたはMSXML6(スレッドによって呼び出される)はスレッドハンドルをコピーしますか?どのようにそれらを閉じることができますか?

私の質問が明確で、ルールを壊さないことを願っています。それは私の最初の質問であり、英語は私の最初の言語ではありません。:-(

言及するのを忘れました。スレッドが終了すると、_beginthreadexによって返されるハンドルを閉じます。これにより、開いているハンドルの数が約半分に減りますが、仮想メモリには影響しません。さらに、CloseHandle呼び出しを挿入する前に、ProcessExplorerに表示される各スレッドハンドルのスレッドのハンドル数は2でした。

編集

以前はこれを含めなかったのでバカになりました。VisualStudioでデバッグしているときにアクティブなスレッドの数が増えないため、スレッドが終了することを知っています。また、リークされたメモリのすべてが、かなり大きなライブラリで使用されているTerminateThreadの呼び出しの結果であるとは限らないことを願っています。また、それを変更したくないと思います。

私の質問のcom部分では、!htrace -diffを使用して、msx​​mlによって割り当てられたが、関数呼び出しの終了後に解放されなかったスレッドハンドルを見つけました。これらはリークに関連しているのでしょうか、それとも後で閉じられるのでしょうか。

それらすべてのコメントに感謝しますが、問題はまだそこにありますが、彼らは私がそれをよりよく理解するのを助けました。

4

2 に答える 2

4

プロセスが使用できる仮想メモリは、4Gb アドレス空間のうち 2Gb です。各スレッドは、スタック スペース用にデフォルトで約 1Mb の仮想メモリ スペースを予約します。したがって、win32 アプリケーションでは、仮想メモリが使い果たされる前に、約 2000 のライブ スレッドの制限があります。

仮想メモリは、アプリケーションが最新の仮想メモリ OS のような Windows で取得するメモリです。Win32 では、アプリケーションに 2Gb の仮想アドレス空間が与えられます。プログラムが new または malloc を呼び出すと、いくつかのレイヤーをトンネリングした後、ページファイル内のディスク上のアプリケーションにスペースが割り当てられます。CPU 命令がそのメモリにアクセスしようとすると、ハードウェア例外がスローされ、カーネルが物理 RAM をその領域に割り当て、ページファイルから内容を読み取ります。そのため、PC の物理 RAM に関係なく、すべてのアプリケーションは 2Gb 全体にアクセスできると認識しています。仮想メモリは、2Gb スペースのどれだけが使用されたかのカウントです。

各スレッド (上記を参照) は、そのスタックが拡大するために 1 Mb の仮想アドレス空間を予約します。その 1Mb のほとんどは、RAM やページファイルの裏付けがない (うまくいけば) 予約済みの領域です。

スレッド ハンドルを閉じても、スレッドは閉じません。スレッドは、TerminateThread を呼び出す別のスレッド (スレッド スタックやその他のリソースをリークするため、絶対に使用しないでください)、ExitThread() 自体を呼び出すか、ThreadProc を終了することによって終了します。

したがって、2000 の呼び出し制限、比類のない CoInitialize および CoUninitialize 呼び出しでは、スレッドが正常に終了していないか、まったく終了していないと言えます。2000 個のワーカー スレッドのそれぞれが、作業を終了した後に終了するのではなく、何らかの処理を行っている状態でスタックしています。

于 2009-11-21T17:48:42.220 に答える
3

_beginthreadex/関数は_endthreadexスレッド ハンドルを自動的に閉じないため、win32CloseHandle関数を呼び出して閉じる必要があります。ハンドルは、 によって返される値_beginthreadexです。_beginthread代わりに/を使用する_endthreadと、ハンドルは自動的に閉じられます。

仮想メモリについて: 予約済みのメモリを表しますが、まだ使用されているとは限りません。リークされたメモリ (または少なくともその一部) は、ハンドル リークに関連しています。スレッドへの最後のハンドルが閉じられると、Windows はそのスレッド用に予約された仮想メモリを解放します。

于 2009-11-21T16:15:13.610 に答える