我们有一个使用WPF / C#.Net 4.0开发的富客户端应用程序,它与内部COM DLL交互。通过包含视频数据的COM接口引发常规事件。
作为应用程序的一部分,我们通过Windows Media Foundation呈现视频,并创建了使用Window Media Foundation的互操作。我们有多个WMF流水线同时渲染不同的视频。
应用程序运行6-8小时呈现视频。在此期间,专用字节始终保持稳定(例如大约500-600MB)。
在某些时候,应用程序似乎挂起,此时私有字节会非常快速地增加,直到进程消耗大约1.4GB的内存并且崩溃并出现OutOfMemoryException。
我们已经在5个不同的工作站上使用不同的图形卡(NVIDIA和ATI卡)以及Windows 7 32和64bit的混合复制了这个。
我们分析了3个转储文件,发现终结器线程正在等待对ole32.GetToSTA()方法的调用。我们无法确定导致终结器线程阻塞的原因以及解决方法。我已经粘贴了我们一直在分析的三个转储的摘录:
转储1)
线程2:ae0正在等待STA线程efc
线程28:efc正在调用WaitForSingleObject。它正在等待的句柄实际上是一个线程句柄5ab4,它是线程ID 14a4
线程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
Dump2)
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
Dump3)
终结器线程在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
关于我们如何解决此问题的任何想法?
答案 0 :(得分:2)
好吧,终结器线程已死锁。这肯定会导致最终的OOM。我们无法看到终结器线程的完整堆栈跟踪,但有些可能会在跟踪中看到SwitchAptAndDispatchCall()和ReleaseRCWListInCorrectCtx(),表明它正在尝试调用IUnknown :: Release()释放COM对象。该对象是单元线程,因此需要一个线程切换来安全地进行调用。
我没有在你发布的堆栈跟踪中看到任何体面的候选人,可能是因为你没有得到正确的候选人,或者线程已经因为异常而忙于关闭。一旦看到虚拟内存大小攀升,请尽快使用调试器中断来捕获它。
这种死锁的最常见原因是违反了STA线程的要求。它必须永远不会阻止哪个状态并且必须泵送消息循环。在.NET程序中通常很容易满足永不阻塞的要求,当您使用 lock 语句或WaitHandle.WaitXxx()调用时,CLR将在必要时抽取消息循环。然而,忘记泵消息循环是很常见的,特别是因为这样做有点痛苦。 Application.Run()是必需的。