0

我有一个 Windows wcf Web 应用程序,在服务端,我们创建有状态会话。当会话数超过某个阈值时,新请求会在 .net 级别排队。我们认为这是因为一些 .net 错误,当对 .net 默认线程池线程的需求突然激增时,.net 无法足够快地发出线程。因此,新请求将排队,直到 .net 从挂起中恢复并发出 thradpool 线程以接受传入请求。

我们正试图弄清楚对线程的突然需求来自何处。当线程数开始增加时,我转储了 w3wp 进程。

我在 windbg 中运行了!uniqstack命令,我注意到下面的堆栈常见于近 400 个线程。这个堆栈是什么意思?这一切都在等待一些 IO 完成吗?这 400 个线程是 IO Completion Port 线程吗?

.561  Id: c504.ce10 Suspend: 0 Teb: 00000038`f6d90000 Unfrozen
      Start: clr!Thread::intermediateThreadProc (00007ff9`d1bbc150)
      Priority: 0  Priority class: 32  Affinity: fff
 # Child-SP          RetAddr           Call Site
00 00000038`f997f068 00007ff9`dfbabcff ntdll!ZwRemoveIoCompletion+0x14 [d:\rs1.obj.amd64fre\minkernel\ntdll\daytona\objfre\amd64\usrstubs.asm @ 251]
01 00000038`f997f070 00007ff9`d1ccea3c KERNELBASE!GetQueuedCompletionStatus+0x3f [d:\rs1\minkernel\kernelbase\error.c @ 844]
02 00000038`f997f0d0 00007ff9`d1bbc1cf clr!ThreadpoolMgr::CompletionPortThreadStart+0x210 [f:\dd\ndp\clr\src\vm\win32threadpool.cpp @ 3770]
03 00000038`f997f170 00007ff9`e1c184d4 clr!Thread::intermediateThreadProc+0x86 [f:\dd\ndp\clr\src\vm\threads.cpp @ 2872]
04 00000038`f997fb30 00007ff9`e285e8b1 kernel32!BaseThreadInitThunk+0x14 [d:\rs1\base\win32\client\thread.c @ 64]
05 00000038`f997fb60 00000000`00000000 ntdll!RtlUserThreadStart+0x21 [d:\rs1\minkernel\ntdll\rtlstrt.c @ 997]

但是按照以下命令,IO Completion 端口线程的数量很少。

0:000> !threadpool
CPU utilization: 3%
Worker Thread: Total: 492 Running: 492 Idle: 0 MaxLimit: 32767 MinLimit: 360
Work Request in Queue: 1
    AsyncTimerCallbackCompletion TimerInfo@000001e7a14ffcd0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 3 Free: 3 MaxFree: 24 CurrentLimit: 3 MaxLimit: 1000 MinLimit: 12
4

2 回答 2

1

前 Microsoft 升级工程师 Tess Ferrandez 似乎准确地将您的案例列为要忽略的事情之一。在她的网站上,如果它坏了,你应该修复它,它是这样提到的:

空闲 CLR 完成端口/IO 线程

14 Id: efc.11c8 Suspend: 1 Teb: fff8e000 Unfrozen
ChildEBP RetAddr Args to Child 
0209fe7c 7d50664c 00000234 0209fee8 0209fec0 ntdll!NtRemoveIoCompletion+0x15
0209fea8 79f795de 00000234 0209feec 0209fee8 kernel32!GetQueuedCompletionStatus+0x29
0209ff14 79f7997f 00000000 00000000 00000000 mscorwks!ThreadpoolMgr::CompletionPortThreadStart+0x11a
0209ffb8 7d4dfff1 0019c440 00000000 00000000 mscorwks!ThreadpoolMgr::intermediateThreadProc+0x49
0209ffec 00000000 79f79939 0019c440 00000000 kernel32!BaseThreadStart+0x34

我不知道为什么!threadpool不认识他们。

于 2019-12-22T23:26:19.183 回答
0

既然你有 WinDbg ;-) 我不是专家,但我拼凑了一些有用的命令,比如两个:

从加载的东西中搜索通配符函数,这将给出在函数处设置断点的确切名称:

x *!*CreateThread*

在函数处设置跟踪点,在深度处记录调用堆栈:

bp ntdll!ZwCreateThreadEx "k 10; gc"

也许这将提供一些关于什么触发了新线程的创建的见解,也许将线程添加到现有池中。

WinDbg 策略也有很多不错的参考站点,例如http://www.windbg.info/,这是我知识不足的限制。

还有 WCF 的参考源,但它相当大,如果您有一些调用堆栈上下文并且知道要在源中搜索什么,那将真的很有帮助。

于 2019-12-19T00:29:23.477 回答