0

我有一个间歇性挂起的多线程 .NET Windows 服务——可能每两周 24/7 运行一次。当挂起发生时,线程池完全饱和,因为对我们自定义跟踪侦听器的调用由于某种原因开始阻塞。根据windbg,违规代码中没有任何锁,也没有任何阻塞,但它们肯定在某个地方阻塞。堆栈上也没有任何异常。在 BufferedStream.Write 代码中偶尔会遇到一个 Thread.Sleep(1),但我的问题是 ReOpenMetaDataWithMemory、CreateApplicationContext 和 DllCanUnloadNow 是什么意思?

ThreadPool 上几乎所有 2000 个挂起的工作线程(不是正常操作!)都有一个类似于以下的堆栈:

0:027> !dumpstack
OS Thread Id: 0x1638 (27)
Child-SP         RetAddr          Call Site
000000001d34df58 0000000077d705d6 ntdll!ZwDelayExecution+0xa
000000001d34df60 000006427f88901d kernel32!SleepEx+0x96
000000001d34e000 000006427f454379 mscorwks!DllCanUnloadNowInternal+0xf53d
000000001d34e080 000006427fa34749 mscorwks!CreateApplicationContext+0x41d
000000001d34e0e0 0000064280184902 mscorwks!ReOpenMetaDataWithMemory+0x1ff59
000000001d34e290 0000064280184532 Company_Common_Diagnostics!Company.Common.Diagnostics.BufferedStream.Write(Byte[], Int32, Int32)+0x1b2
000000001d34e300 00000642801831fd Company_Common_Diagnostics!Company.Common.Diagnostics.XmlRollingTraceListener+TraceWriter.Write(System.String)+0x52
000000001d34e350 00000642801b3304 Company_Common_Diagnostics!Company.Common.Diagnostics.XmlRollingTraceListener.InternalWrite(System.Text.StringBuilder)+0x3d
000000001d34e390 0000064274e9d7ec Company_Common_Diagnostics!Company.Common.Diagnostics.XmlRollingTraceListener.TraceTransfer(System.Diagnostics.TraceEventCache, System.String, Int32, System.String, System.Guid)+0xc4
000000001d34e410 00000642801b2f59 System_ni!System.Diagnostics.TraceSource.TraceTransfer(Int32, System.String, System.Guid)+0x2ec
4

4 回答 4

2

不是真正的答案,而是要检查的东西...

确保您的跟踪源中还没有注册 DefaultTraceListener。如果您没有明确清除删除DefaultTraceListener它可能仍然存在。DefaultTraceListener的IsThreadSafe属性返回false,在这种情况下 System.Diagnostics.Trace 类围绕TraceEvent()调用 创建一个lock() 。

只是需要注意的事情。

更多信息:

TraceListener.IsThreadSafe 属性

IsThreadSafe 的值用于确定在写入侦听器时是否使用全局锁。如果 IsThreadSafe 的值为 false,则无论 UseGlobalLock 的值如何,都会使用全局锁。仅当 IsThreadSafe 的值为 true 且 UseGlobalLock 的值为 false 时才使用全局锁。默认行为是在写入侦听器时使用全局锁。

谢谢,亚伦

于 2009-02-21T23:33:20.430 回答
1

事实上,这些函数的偏移量似乎很大(mscorwks!ReOpenMetaDataWithMemory+0x1ff59),我会说你没有 mscorwks 的符号。

使用以下方法设置本地符号存储:

.symfix+ c:\websymbols
.reload mscorwks.dll
其中 c:\websymbols 是您为系统符号选择的路径。这应该为您提供合理的函数名称,从中调用 kernel32!Sleep。

至于其余的,所有其他挂起线程的堆栈是什么样的?另外,您也可以发布本机堆栈(kb)吗?

于 2009-01-27T21:37:35.883 回答
0

你是对的。

大约有 2000 个挂起的线程,它们上的堆栈跟踪几乎相同。代码中有一个 KeepAlive 函数,每 1 秒响一次。丁代码周围有一个monitor.tryenter。如果它无法获得锁,它会发出跟踪。这就是所有这些线程正在做的事情。具有锁 (18) 的线程几乎具有相同的堆栈跟踪。

有没有办法在 BufferedStream 类中查看局部变量,看看它是否卡在循环中?

0:047> kb
RetAddr           : Args to Child                                                           : Call Site
00000000`77d705d6 : ffffffff`fffffffe 00000000`00000000 00000000`00000000 00000000`1ef7f160 : ntdll!ZwDelayExecution+0xa
00000642`7f88901d : 00000000`00000029 00000642`00000001 00000000`00000000 00000000`1c00f820 : kernel32!SleepEx+0x96
00000642`7f454379 : 00000000`00c70128 00000642`7fa2b159 00000000`00000001 00000000`00000001 : mscorwks!EESleepEx+0x2d
00000642`7fa34749 : 06000000`00000001 00000000`1c00f820 00000000`00c6ff08 00000000`00000001 : mscorwks!Thread::UserSleep+0x71
00000642`80184902 : 00000000`00000001 00000642`782f1950 00000000`015695e0 00000000`00000000 : mscorwks!ThreadNative::Sleep+0xf9
00000642`80184532 : 00000000`00c6fe90 00000642`783924e2 00000000`00db11d8 00000000`00000008 : 0x642`80184902
00000642`801831fd : 00000000`00c6fe90 00000000`00000008 00000642`80043680 00000000`00c02d58 : 0x642`80184532
00000642`74e9e494 : ffffffff`fffffffe 00000000`00000001 0000c0c9`0263a71f 00000642`7f361300 : 0x642`801831fd
00000642`8018d3d3 : 00000000`00c02d58 00000000`00000008 00000000`00000000 00000000`00db11d8 : System_ni+0x61e494
00000642`782f173b : 00000000`00c036a0 00000642`7834901c 00000642`78431598 00000000`77ef9971 : 0x642`8018d3d3
00000642`7834d696 : 00000000`00a061b0 00000000`00400080 00000000`00000000 00000642`7f529408 : mscorlib_ni+0x2f173b
00000642`7f602672 : 00000000`00db0cb8 000007ff`7d370000 000007ff`7d370000 000007ff`fffdb000 : mscorlib_ni+0x34d696
00000642`7f50c053 : 00000642`7f39f3f6 00000000`77dbc178 00000000`00000000 00000000`00000000 : mscorwks!CallDescrWorker+0x82
00000642`7f51449a : 00000000`1ef7f9f8 ffffffff`fffffffe 00000000`00000000 00000000`77d6f447 : mscorwks!CallDescrWorkerWithHandler+0xd3
00000642`7f46b023 : 00000000`00000001 00000000`77d6f491 00000000`00000000 00000000`1ee81000 : mscorwks!DispatchCallDebuggerWrapper+0x3e
00000642`7f41729e : 00000000`1ef7fb88 00000000`1c00f801 00000000`00000001 00000000`1c00f820 : mscorwks!DispatchCallNoEH+0x5f
00000642`7f447ee8 : 00000000`00db0cb8 00000000`00db0cb8 00000000`00000001 00000642`7f50946a : mscorwks!AddTimerCallback_Worker+0x92
00000642`7f556aa9 : 00000000`00000001 00000000`00000000 ffffffff`fffffffe 00000000`1ef7fba8 : mscorwks!Thread::DoADCallBack+0x488
00000642`7f43afdd : 00000000`001597d0 00000000`1c00f820 00000000`1ef7fab0 00000000`0019fcb0 : mscorwks!CNgenEntryBind::Create+0x15d
00000642`7f435296 : 00000000`1ef7fba8 ffffffff`ffffffff 00000000`1c00f820 00000642`7f885bdb : mscorwks!MethodTable::IsAbstract+0x49
0:047> !dumpstack
OS Thread Id: 0x15b0 (47)
Child-SP         RetAddr          Call Site
000000001ef7f138 0000000077d705d6 ntdll!ZwDelayExecution+0xa
000000001ef7f140 000006427f88901d kernel32!SleepEx+0x96
000000001ef7f1e0 000006427f454379 mscorwks!EESleepEx+0x2d
000000001ef7f260 000006427fa34749 mscorwks!Thread::UserSleep+0x71
000000001ef7f2c0 0000064280184902 mscorwks!ThreadNative::Sleep+0xf9
000000001ef7f470 0000064280184532 Company_Common_Diagnostics!Company.Common.Diagnostics.BufferedStream.Write(Byte[], Int32, Int32)+0x1b2
000000001ef7f4e0 00000642801831fd Company_Common_Diagnostics!Company.Common.Diagnostics.XmlRollingTraceListener+TraceWriter.Write(System.String)+0x52
000000001ef7f530 0000064274e9e494 Company_Common_Diagnostics!Company.Common.Diagnostics.XmlRollingTraceListener.InternalWrite(System.Text.StringBuilder)+0x3d
000000001ef7f570 000006428018d3d3 System_ni!System.Diagnostics.TraceSource.TraceEvent(System.Diagnostics.TraceEventType, Int32, System.String)+0x2b4
000000001ef7f620 00000642782f173b Company_Common_Routing_Service!Company.Common.RouterService.KeepAlive(System.Object)+0x2a3
000000001ef7f6f0 000006427834d696 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x9b
000000001ef7f740 000006427f602672 mscorlib_ni!System.Threading._TimerCallback.PerformTimerCallback(System.Object)+0x86
000000001ef7f790 000006427f50c053 mscorwks!CallDescrWorker+0x82
000000001ef7f7e0 000006427f51449a mscorwks!CallDescrWorkerWithHandler+0xd3
000000001ef7f880 000006427f46b023 mscorwks!DispatchCallDebuggerWrapper+0x3e
000000001ef7f8e0 000006427f41729e mscorwks!DispatchCallNoEH+0x5f
000000001ef7f960 000006427f447ee8 mscorwks!AddTimerCallback_Worker+0x92
000000001ef7f9f0 000006427f556aa9 mscorwks!Thread::DoADCallBack+0x488
000000001ef7fa40 000006427f43afdd mscorwks!CNgenEntryBind::Create+0x15d
000000001ef7fb10 000006427f435296 mscorwks!MethodTable::IsAbstract+0x49
000000001ef7fb50 000006427f4162bb mscorwks!AddTimerCallbackEx+0xba
000000001ef7fc10 000006427f495fa7 mscorwks!ThreadpoolMgr::AsyncTimerCallbackCompletion+0x53
000000001ef7fc70 000006427f4aad0a mscorwks!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x157
000000001ef7fd10 000006427f41f9a0 mscorwks!ThreadpoolMgr::WorkerThreadStart+0x1ba
000000001ef7fdb0 0000000077d6b6da mscorwks!Thread::intermediateThreadProc+0x78
000000001ef7ff80 0000000000000000 kernel32!BaseThreadStart+0x3a
于 2009-01-27T23:00:30.787 回答
0

想通了,我相信。我进入 BufferStream 并看到它处于这样一种状态:任何调用 TraceListener 的东西都会卡在 Thread.Sleep(1) 循环中。我希望这是解决方法,因为我无法终生重现该问题。

我在跟踪配置中有 usegloballock=false 和 autoflush=true 。TraceListener 上的 flush 方法不是线程安全的 - 侦听器旨在使用数据缓冲,因此有时 TraceListener 会在刷新和写入并发时处于错误状态。解决方法是简单地设置 autoflush=false。我不敢相信我没有早点抓住这个。

于 2009-01-27T23:39:42.563 回答