终结者阻止的问题

时间:2018-08-08 10:03:26

标签: multithreading finalizer blocked

hi,我搜索了有关永久阻止的终结器线程的各种帖子和答案。几个似乎有用,但我需要进一步说明。

在我的应用程序中,API调用是从Web服务到NT服务。我正在测试环境中工作,可以一遍又一遍地重现此“效果”。在我的测试中,我将遵循以下一般步骤:

  1. 在Visual Studio(10个用户)中运行负载测试,以进行API调用模式。 (我的负载测试时间设置为99小时,这样我就可以连续运行它,并在想要停止负载并检查过程条件时简单地中止测试。)
  2. 启动Perfmon并监视密钥统计信息,专用字节,虚拟字节,线程,句柄,GC中的#time等...
  3. 停止负载测试。
  4. 将Windbg附加到该过程。检查是否出了问题。 (FinalizeQueue等)
  5. 如果没有问题,请分离并重新启动负载测试。

我将遵循此常规过程,并更改测试以检查各种API调用,以查看这些API对应用程序的内存配置文件的作用。

在进行此操作时,我注意到偶尔停止负载测试时,会出现“线程被中止”异常。在客户环境的日志中也很少看到这种情况。进行API调用后,无论出于何种原因,客户端都将断开连接。

但是,在收到此异常之后,我注意到我的过程的终结器已挂起。 (NT类服务,而不是w3wp。)

无论该过程不负担多长时间,这都是!finalizequeue输出的顶部:

    0:002> !finalizequeue
    SyncBlocks to be cleaned up: 0
    Free-Threaded Interfaces to be released: 0
    MTA Interfaces to be released: 0
    STA Interfaces to be released: 0
    ----------------------------------
    generation 0 has 15 finalizable objects (0c4b3db8->0c4b3df4)
    generation 1 has 9 finalizable objects (0c4b3d94->0c4b3db8)
    generation 2 has 771 finalizable objects (0c4b3188->0c4b3d94)
    Ready for finalization 178 objects (0c4b3df4->0c4b40bc)

我可以通过调用API来添加对象“ Ready For Finalization”,但是Finalizer线程似乎永远不会移动并清空列表。

上面显示的终结器线程是线程002。这是调用堆栈:

    0:002> !clrstack
    OS Thread Id: 0x29bc (2)
    Child SP       IP Call Site
    03eaf790 77b4f29c [DebuggerU2MCatchHandlerFrame: 03eaf790] 
    0:002> kb 2000
     # ChildEBP RetAddr  Args to Child              
    00 03eae910 773a2080 00000001 03eaead8 00000001 ntdll!NtWaitForMultipleObjects+0xc
    01 03eaeaa4 77047845 00000001 03eaead8 00000000 KERNELBASE!WaitForMultipleObjectsEx+0xf0
    02 03eaeaf0 770475f5 05b72fb8 00000000 ffffffff combase!MTAThreadWaitForCall+0xd5 [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 7290] 
    03 03eaeb24 77018457 03eaee5c 042c15b8 05b72fb8 combase!MTAThreadDispatchCrossApartmentCall+0xb5 [d:\rs1\onecore\com\combase\dcomrem\chancont.cxx @ 227] 
    04 (Inline) -------- -------- -------- -------- combase!CSyncClientCall::SwitchAptAndDispatchCall+0x38a [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 6050] 
    05 03eaec40 76fbe16b 03eaee5c 03eaee34 03eaee5c combase!CSyncClientCall::SendReceive2+0x457 [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 5764] 
    06 (Inline) -------- -------- -------- -------- combase!SyncClientCallRetryContext::SendReceiveWithRetry+0x29 [d:\rs1\onecore\com\combase\dcomrem\callctrl.cxx @ 1734] 
    07 (Inline) -------- -------- -------- -------- combase!CSyncClientCall::SendReceiveInRetryContext+0x29 [d:\rs1\onecore\com\combase\dcomrem\callctrl.cxx @ 632] 
    08 03eaec9c 77017daa 05b72fb8 03eaee5c 03eaee34 combase!DefaultSendReceive+0x8b [d:\rs1\onecore\com\combase\dcomrem\callctrl.cxx @ 590] 
    09 03eaee10 76f72fa5 03eaee5c 03eaee34 03eaf3d0 combase!CSyncClientCall::SendReceive+0x68a [d:\rs1\onecore\com\combase\dcomrem\ctxchnl.cxx @ 767] 
    0a (Inline) -------- -------- -------- -------- combase!CClientChannel::SendReceive+0x7c [d:\rs1\onecore\com\combase\dcomrem\ctxchnl.cxx @ 702] 
    0b 03eaee3c 76e15eea 05b59e04 03eaef48 17147876 combase!NdrExtpProxySendReceive+0xd5 [d:\rs1\onecore\com\combase\ndr\ndrole\proxy.cxx @ 1965] 
    0c 03eaf358 76f73b30 76f5bd70 76f84096 03eaf390 rpcrt4!NdrClientCall2+0x53a
    0d 03eaf378 7706313f 03eaf390 00000008 03eaf420 combase!ObjectStublessClient+0x70 [d:\rs1\onecore\com\combase\ndr\ndrole\i386\stblsclt.cxx @ 217] 
    0e 03eaf388 77026d85 05b59e04 03eaf3d0 011d0940 combase!ObjectStubless+0xf [d:\rs1\onecore\com\combase\ndr\ndrole\i386\stubless.asm @ 171] 
    0f 03eaf420 77026f30 011d0930 73b1a9e0 03eaf4e4 combase!CObjectContext::InternalContextCallback+0x255 [d:\rs1\onecore\com\combase\dcomrem\context.cxx @ 4401] 
    10 03eaf474 73b1a88b 011d0940 73b1a9e0 03eaf4e4 combase!CObjectContext::ContextCallback+0xc0 [d:\rs1\onecore\com\combase\dcomrem\context.cxx @ 4305] 
    11 03eaf574 73b1a962 73b689d0 03eaf60c b42b9326 clr!CtxEntry::EnterContext+0x252
    12 03eaf5ac 73b1a9a3 73b689d0 03eaf60c 00000000 clr!RCW::EnterContext+0x3a
    13 03eaf5d0 73b1eed3 03eaf60c b42b936a 740ecf60 clr!RCWCleanupList::ReleaseRCWListInCorrectCtx+0xbc
    14 03eaf62c 73b6118f b42b90f6 03eaf790 00000000 clr!RCWCleanupList::CleanupAllWrappers+0x119
    15 03eaf67c 73b61568 03eaf790 73b60f00 00000001 clr!SyncBlockCache::CleanupSyncBlocks+0xd0
    16 03eaf68c 73b60fa9 b42b9012 03eaf790 73b60f00 clr!Thread::DoExtraWorkForFinalizer+0x75
    17 03eaf6bc 73a7b4c9 03eaf7dc 011a6248 03eaf7dc clr!FinalizerThread::FinalizerThreadWorker+0xba
    18 03eaf6d0 73a7b533 b42b91fe 03eaf7dc 00000000 clr!ManagedThreadBase_DispatchInner+0x71
    19 03eaf774 73a7b600 b42b915a 73b7a760 73b60f00 clr!ManagedThreadBase_DispatchMiddle+0x7e
    1a 03eaf7d0 73b7a758 00000001 00000000 011b3120 clr!ManagedThreadBase_DispatchOuter+0x5b
    1b 03eaf7f8 73b7a81f b42b9ebe 73b7a760 00000000 clr!ManagedThreadBase::FinalizerBase+0x33
    1c 03eaf834 73af15a1 00000000 00000000 00000000 clr!FinalizerThread::FinalizerThreadStart+0xd4
    1d 03eaf8d0 753c62c4 011ae320 753c62a0 c455bdb0 clr!Thread::intermediateThreadProc+0x55
    1e 03eaf8e4 77b41f69 011ae320 9d323ee5 00000000 kernel32!BaseThreadInitThunk+0x24
    1f 03eaf92c 77b41f34 ffffffff 77b6361e 00000000 ntdll!__RtlUserThreadStart+0x2f
    20 03eaf93c 00000000 73af1550 011ae320 00000000 ntdll!_RtlUserThreadStart+0x1b

通过重复几次,我得到了“线程被中止”异常的关联,并且每次都使用此调用堆栈获得了挂起的终结器。任何人都可以提供有关终结器正在等待什么的澄清,以及其他可能有助于确定解决方案的相关问题吗?

谢谢?随时问您是否需要更多信息。

编辑后的添加项如下: 在阅读了汉斯的分析报告后,我的主管向我发送了System.ComponentModel.Component的代码,我需要尝试对这一点进行澄清。 (即使我发送的代码某种程度上是错误的版本。)

以下是System.ComponentModel.Component的终结器:

    ~Component() {
        Dispose(false);
    }

这里是Dispose(布尔):

    protected virtual void Dispose(bool disposing) {
        if (disposing) {
            lock(this) {
                if (site != null && site.Container != null) {
                    site.Container.Remove(this);
                }
                if (events != null) {
                    EventHandler handler = (EventHandler)events[EventDisposed];
                    if (handler != null) handler(this, EventArgs.Empty);
                }
            }
        }
    }

希望我不会在这里犯一个愚蠢的错误,但是如果终结器线程仅调用Dispose(false),则它可能无法阻止任何内容。如果那是真的,那我是不是树错了树?我应该再找其他班吗?

如何使用转储文件确定终结器所挂在的实际对象类型?

第二次修改: 我运行了负载测试,并监视了最终生存者,直到我开始看到它上升。然后,我停止了负载测试。结果是即使我几次造成GC,最终幸存者也“卡在” 88,并且从未下降。我重置并重新启动了SQL Server,但该统计数据仍然停留在88。

我转储了该过程,并捕获了finalizequeue输出,虽然对此感到困惑,但我注意到perfmon在转储大约15分钟后突然注册了finalize幸存者。

我进行了另一个转储,并重新捕获了finalizequeue输出,并将其与前一个进行比较。大多数都相同,但有以下区别:

    B   A   Diff    
    4   0   -4  System.Transactions.SafeIUnknown
    6   0   -6  OurCompany.Xpedite.LogOutResponseContent
    20  0   -20 System.Net.Sockets.OverlappedCache
    8   2   -6  System.Security.SafeBSTRHandle
    21  3   -18 System.Net.SafeNativeOverlapped
    6   4   -2  Microsoft.Win32.SafeHandles.SafeFileHandle
    8   9   1   System.Threading.ThreadPoolWorkQueueThreadLocals
    19  1   -18 System.Net.Sockets.OverlappedAsyncResult
    7   2   -5  System.Data.SqlClient.SqlDataAdapter
    7   2   -5  System.Data.DataSet
    13  7   -6  OurCompany.Services.Messaging.Message
    79  13  -66 Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
    6   4   -2  System.IO.FileStream
    24  3   -21 System.Data.SqlClient.SqlConnection
    40  22  -18 Microsoft.Win32.SafeHandles.SafeWaitHandle
    17  3   -14 System.Data.SqlClient.SqlCommand
    14  4   -10 System.Data.DataColumn
    7   2   -5  System.Data.DataTable
    21  20  -1  System.Threading.Thread
    73  68  -5  System.Threading.ReaderWriterLock

0 个答案:

没有答案