.net - 我如何找到挂起的终结器队列的原因?

标签 .net finalizer

我有一个应用程序,从单词go经历了缓慢的内存泄漏。

使用ANTS Memory Profiler,我可以看到所有泄漏的内存都由终结器队列的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()是将请求编码(marshal)给拥有COM对象的STA的调用。

    典型的原因是创建COM对象,而不是发送消息循环。对STA线程的严格要求。通过在主UI线程上创建它们并从不对其进行阻止,可以避免这种情况。

    关于.net - 我如何找到挂起的终结器队列的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7704805/

    相关文章:

    c# - 数组中更改的项目是否进入垃圾收集?

    .net - 使用 1 个 OracleCommand 填充多个数据表

    python - Python 中的 __del__() 方法有什么用?

    java - 如果我在对象的 Finalize 方法中保存对对象的引用,该对象是否会被 GC 回收?

    c# - Dispose() 方法中 GC.SuppressFinalize(this) 的目的是什么?

    .net - 扩展方法是否太昂贵?

    c# - 我正在尝试使用 linq 简化一个语句,该语句采用 2 个数字列表并从第二个数字中减去第一个数字

    F# 等价于析构函数

    java - 如何使用 PhantomReference 作为 finalize() 的替代

    .net - 终结器线程的范围是什么 - 每个应用程序域或每个进程?