如何找到挂起终结器队列的原因?



我有一个应用程序从一开始就经历了缓慢的内存泄漏。

使用ANTS内存分析器我可以看到所有泄漏的内存都由终结器队列的GC根持有。

我怀疑可能发生的事情是终结器在等待锁可用时死锁了。

我们的所有类都没有实现显式终结器,我们通常避免使用它们,这使我认为锁可能与系统或库类有关。

我已经使用SOS.dll来查看终结器队列的内容,如果我正确地解释了它,那么它报告的第一个项目是一个实例System.Threading.Thread,但是我不确定队列的头部是否实际上代表当前被处置的对象或下一个要处置的对象。

  • 我可以使用什么技巧来找出正在完成的内容吗?
  • 是否有一种方法可以找出终结器线程正在等待的锁?
  • 可以打开任何额外的调试来跟踪终结器线程的动作吗?
  • 我还能看什么?

终结器线程的堆栈如下所示:

ntdll.dll!_ZwWaitForSingleObject@12()  + 0x15 bytes  
ntdll.dll!_ZwWaitForSingleObject@12()  + 0x15 bytes  
user32.dll!_NtUserPostMessage@16()  + 0x15 bytes     
kernel32.dll!_WaitForSingleObjectExImplementation@12()  + 0x43 bytes     
kernel32.dll!_WaitForSingleObject@8()  + 0x12 bytes  
ole32.dll!GetToSTA()  + 0x72 bytes   
ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall()  - 0x1939 bytes  
ole32.dll!CRpcChannelBuffer::SendReceive2()  + 0xa6 bytes    
ole32.dll!CAptRpcChnl::SendReceive()  + 0x5b7 bytes  
ole32.dll!CCtxComChnl::SendReceive()  - 0x14b97 bytes    
ole32.dll!NdrExtpProxySendReceive()  + 0x43 bytes    
rpcrt4.dll!@NdrpProxySendReceive@4()  + 0xe bytes    
rpcrt4.dll!_NdrClientCall2()  + 0x144 bytes  
ole32.dll!_ObjectStublessClient@8()  + 0x7a bytes    
ole32.dll!_ObjectStubless@0()  + 0xf bytes   
ole32.dll!CObjectContext::InternalContextCallback()  - 0x511f bytes  
ole32.dll!CObjectContext::ContextCallback()  + 0x8f bytes    
clr.dll!CtxEntry::EnterContext()  + 0x119 bytes  
clr.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx()  + 0x2bb bytes  
clr.dll!RCWCleanupList::CleanupAllWrappers()  - 0x20fb0 bytes    
clr.dll!SyncBlockCache::CleanupSyncBlocks()  + 0x1ec6 bytes  
clr.dll!Thread::DoExtraWorkForFinalizer()  + 0x411b5 bytes   
clr.dll!WKS::GCHeap::FinalizerThreadWorker()  + 0x8b bytes   
clr.dll!Thread::DoExtraWorkForFinalizer()  + 0xb6e76 bytes   
clr.dll!Thread::ShouldChangeAbortToUnload()  - 0x5f8 bytes   
clr.dll!Thread::ShouldChangeAbortToUnload()  - 0x53d bytes   
clr.dll!ManagedThreadBase_NoADTransition()  + 0x35 bytes     
clr.dll!ManagedThreadBase::FinalizerBase()  + 0xf bytes  
clr.dll!WKS::GCHeap::FinalizerThreadStart()  + 0xfb bytes    
clr.dll!Thread::intermediateThreadProc()  + 0x48 bytes   
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes     
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes    
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes     

看来你有一个COM服务器的问题。调用堆栈显示它正在尝试对单线程COM对象进行IUnknown::Release()调用。ReleaseRCWListInCorrectCtx()调用将其关闭,_NtUserPostMessage@16()调用将请求封送到拥有COM对象的STA。

典型的原因是创建COM对象而没有抽取消息循环。STA线程的硬性要求。您可以通过在主UI线程上创建它们并且不阻塞它来避免它。

最新更新