2

社内の COM DLL と相互運用する WPF/C#.Net 4.0 を使用して開発されたリッチ クライアント アプリケーションがあります。通常のイベントは、ビデオ データを含むこの COM インターフェイスを介して発生します。

アプリケーションの一部として、Windows Media Foundation を介してビデオをレンダリングし、Window Media Foundation を使用するための相互運用機能を作成しました。同時に異なるビデオをレンダリングする複数の WMF パイプラインがあります。

アプリケーションは、ビデオのレンダリングに 6 ~ 8 時間実行されます。この間、プライベート バイトは一貫して安定しています (たとえば、約 500 ~ 600MB)。

ある時点で、アプリケーションがハングしたように見えます。この時点で、プロセスが約 1.4 GB のメモリを消費し、OutOfMemoryException でクラッシュするまで、プライベート バイトが急速に増加します。

異なるグラフィック カード (NVIDIA および ATI カード) を使用し、Windows 7 32 ビットと 64 ビットが混在する 5 つの異なるワークステーションでこれを再現しました。

3 つのダンプ ファイルを分析したところ、ファイナライザー スレッドが ole32.GetToSTA() メソッドの呼び出しを待機していることがわかりました。ファイナライザー スレッドがブロックされる原因と、これを解決する方法を特定できません。私たちが分析してきた 3 つのダンプからの抜粋を貼り付けました。

ダンプ 1)

スレッド 2:ae0 は STA スレッド efc で待機しています

スレッド 28:efc は WaitForSingleObject を呼び出しています。待機中のハンドルは、実際にはスレッド ID 14a4 のスレッド ハンドル 5ab4 です。

スレッド 130:14a4 には次のスタックがあります。

37f4fdf4 753776a6 ntdll!NtRemoveIoCompletion+0x15
37f4fe20 63301743 KERNELBASE!GetQueuedCompletionStatus+0x29
37f4fe74 6330d0db WMNetMgr!CNSIoCompletionPortNT::WaitAndServeCompletionsLoop+0x5e
37f4fe94 633199bf WMNetMgr!CNSIoCompletionPortNT::WaitAndServeCompletions+0x4c
37f4fecc 63312dbd WMNetMgr!CWorkThreadManager::CWorkerThread::ThreadMain+0xa2
37f4fed8 769b3677 WMNetMgr!CWMThread::ThreadFunc+0x3b
37f4fee4 77679f42 kernel32!BaseThreadInitThunk+0xe
37f4ff24 77679f15 ntdll!__RtlUserThreadStart+0x70
37f4ff3c 00000000 ntdll!_RtlUserThreadStart+0x1b

ダンプ2)

STA スレッド:

1127f474 75f80a91 ntdll!ZwWaitForSingleObject+0x15
1127f4e0 77411184 KERNELBASE!WaitForSingleObjectEx+0x98
1127f4f8 77411138 kernel32!WaitForSingleObjectExImplementation+0x75
1127f50c 63ae5f29 kernel32!WaitForSingleObject+0x12
1127f530 63a8eb2e WMNetMgr!CWMThread::Wait+0x78
1127f54c 63a8f128 WMNetMgr!CWorkThreadManager::CThreadPool::Shutdown+0x70
1127f568 63a76e10 WMNetMgr!CWorkThreadManager::Shutdown+0x34
1127f59c 63a76f2d WMNetMgr!CNSClientNetManagerHelper::Shutdown+0xdd
1127f5a4 63cd228e WMNetMgr!CNSClientNetManager::Shutdown+0x66
WARNING: Stack unwind information not available. Following frames may be wrong.
1127f5bc 63cd23a6 WMVCORE!WMCreateProfileManager+0xeef6
1127f5dc 63c573ca WMVCORE!WMCreateProfileManager+0xf00e
1127f5e8 63c62f18 WMVCORE!WMIsAvailableOffline+0x2ba3b
1127f618 63c19da6 WMVCORE!WMIsAvailableOffline+0x37589
1127f630 63c1aca2 WMVCORE!WMIsContentProtected+0x56e4
1127f63c 63c14bd7 WMVCORE!WMIsContentProtected+0x65e0
1127f650 113de6e8 WMVCORE!WMIsContentProtected+0x515
1127f660 113de513 wmp!CWMDRMReaderStub::CExternalStub::ShutdownInternalRefs+0x1d0
1127f674 113c1988 wmp!CWMDRMReaderStub::ExternalRelease+0x4f
1127f67c 1160a5b9 wmp!CWMDRMReaderStub::CExternalStub::Release+0x13
1127f6a4 1161745f wmp!CWMGraph::CleanupUpStream_selfprotected+0xbe

ファイナライザ スレッドが STA に切り替えようとしています:

0126eccc 75f80a91 ntdll!ZwWaitForSingleObject+0x15
0126ed38 77411184 KERNELBASE!WaitForSingleObjectEx+0x98
0126ed50 77411138 kernel32!WaitForSingleObjectExImplementation+0x75
0126ed64 75d78907 kernel32!WaitForSingleObject+0x12
0126ed88 75e9a819 ole32!GetToSTA+0xad

ダンプ3)

ファイナライザ スレッドは GetToSTA 呼び出しにあるため、COM オブジェクトが解放されるのを待っています。

スレッド 29 は STA の COM オブジェクトであり、スレッド 53 (1bf4) が所有するクリティカル セクションで待機しています。

スレッド 53 は次のことを行っています。

1cbcf990 76310a91 ntdll!ZwWaitForSingleObject+0x15
1cbcf9fc 74cb1184 KERNELBASE!WaitForSingleObjectEx+0x98
1cbcfa14 74cb1138 kernel32!WaitForSingleObjectExImplementation+0x75
1cbcfa28 65dfb6bb kernel32!WaitForSingleObject+0x12
WARNING: Stack unwind information not available. Following frames may be wrong.
1cbcfa48 74cb3677 wmp!Ordinal3000+0x53280
1cbcfa54 77029f42 kernel32!BaseThreadInitThunk+0xe
1cbcfa94 77029f15 ntdll!__RtlUserThreadStart+0x701cbcfaac 00000000 ntdll!_RtlUserThreadStart+0x1b

この問題を解決する方法について何かアイデアはありますか?

4

1 に答える 1

2

さて、ファイナライザー スレッドはデッドロックです。それは確かに最終的にOOMになります。ファイナライザー スレッドの完全なスタック トレースは確認できませんが、トレースに SwitchAptAndDispatchCall() と ReleaseRCWListInCorrectCtx() が表示される可能性があり、IUnknown::Release() を呼び出して COM オブジェクトを解放しようとしていることを示しています。 . また、そのオブジェクトはアパートメント スレッドであるため、安全に呼び出しを行うにはスレッド スイッチが必要です。

あなたが投稿したスタック トレースに適切な候補が表示されません。おそらく、適切な候補を取得できなかったか、例外のためにスレッドが既にシャットダウン中であるためです。仮想メモリのサイズが大きくなったらすぐに、デバッガー ブレークを使用して早期にキャッチするようにしてください。

このようなデッドロックの最も一般的な原因は、STA スレッドの要件に違反していることです。ブロックしてはならず、メッセージ ループをポンピングする必要がある状態。通常、決してブロックしないという要件は、.NET プログラムで簡単に満たすことができます。CLR は、 lockステートメントまたは WaitHandle.WaitXxx() 呼び出しを使用するときに、必要に応じてメッセージ ループをポンプします。ただし、メッセージ ループをポンピングするのを忘れることは非常によくあることです。Application.Run() が必要です。

于 2012-09-03T13:53:38.007 に答える