在性能监视器中监视我的.NET应用程序我可以看到 .NET CLR LocksAndThreads /当前逻辑线程数随着时间的推移稳步增加(当前为293),这表明线程堆栈正在泄漏。 / p>
我可以找到很多文章告诉我这是问题,但没有任何东西告诉我如何找到原因 - 那么我从哪里开始? Windbg可以告诉我问题出在哪里吗?
这是我3小时的性能监视器,告诉我当前的逻辑线程是150:
这是线程窗口的输出,这并没有告诉我太多因为我无法访问他们的调用堆栈 - 它们大多被标记为[不可用]或[在睡眠中,等待或加入] | [外部代码]:
Unflagged 141024 124 Worker Thread <No Name> Normal
Unflagged > 0 0 Unknown Thread [Thread Destroyed]
Unflagged 136272 2 Worker Thread <No Name> Highest
Unflagged 133060 7 Worker Thread vshost.RunParkingWindow [Managed to Native Transition] Normal
Unflagged 136952 10 Main Thread Main Thread [edited].Program.Main Normal
Unflagged 134544 9 Worker Thread .NET SystemEvents [Managed to Native Transition] Normal
Unflagged 136556 11 Worker Thread Worker Thread [edited].MessageService.ProcessJobs.AnonymousMethod__0 Normal
Unflagged 141364 113 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 140896 0 Worker Thread [Thread Destroyed] Normal
Unflagged 136776 19 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 135704 20 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 136712 21 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 134984 22 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 134660 23 Worker Thread Worker Thread [edited].BroadcastService.ProcessJobs.AnonymousMethod__1d Normal
Unflagged 140224 152 Worker Thread <No Name> Normal
Unflagged 140792 157 Worker Thread <No Name> Normal
Unflagged 137116 0 Worker Thread <No Name> Normal
Unflagged 140776 111 Worker Thread <No Name> Normal
Unflagged 140784 0 Worker Thread [Thread Destroyed] Normal
Unflagged 140068 145 Worker Thread <No Name> Normal
Unflagged 139000 150 Worker Thread <No Name> Normal
Unflagged 140828 52 Worker Thread <No Name> Normal
Unflagged 137752 146 Worker Thread <No Name> Normal
Unflagged 140868 151 Worker Thread <No Name> Normal
Unflagged 141324 139 Worker Thread <No Name> Normal
Unflagged 140168 154 Worker Thread <No Name> Normal
Unflagged 141848 0 Worker Thread [Thread Destroyed] Normal
Unflagged 135544 153 Worker Thread <No Name> Normal
Unflagged 142260 140 Worker Thread <No Name> Normal
Unflagged 141528 142 Worker Thread <No Name> [In a sleep, wait, or join] Normal
Unflagged 141344 0 Worker Thread [Thread Destroyed] Normal
Unflagged 140096 136 Worker Thread <No Name> Normal
Unflagged 141712 134 Worker Thread <No Name> Normal
Unflagged 141688 147 Worker Thread <No Name> Normal
更新 我已经将罪魁祸首追溯到System.Timers.Timer。即使这个计时器在每个Elapsed事件上调用一个空方法,它仍然无限地提升逻辑线程数。只需将计时器更改为DispatcherTimer就可以解决问题。
我在this question中提到的在Windbg中运行!dumpheap -type TimerCallback
后看到一个大数字时,我开始查看我的应用程序中的所有计时器。
我仍然想知道我是如何通过Windbg调试检测到的,而不是通过禁用定时器/检查性能/重复方法来引导我进行修复。即任何可以告诉我哪个计时器正在创造问题的东西。
答案 0 :(得分:4)
这通常是由线程池线程卡住而未完成引起的。每隔半秒,线程池管理器允许另一个线程开始尝试解决积压问题。这一直持续到它达到ThreadPool.SetMaxThreads()设置的最大线程数。默认情况下,4核机器上的数字很大,为1000。
使用Debug + Windows + Threads查看正在运行的线程。他们的调用堆栈应该明确他们阻塞的原因。
答案 1 :(得分:0)
尝试所有长时间运行的操作(100多天数据库调用,磁盘或网络访问)以异步方式运行。
在.NET 4.5中使用async / await原语指令。
如果从线程池队列中检索到排队的任务时没有线程可用,则线程池的线程数会增加。如果趋势在服务器中以这种方式继续,您可能会以线程池饥饿结束。如果线程池队列中充满了任务.net将拒绝更多请求,因此您将处于应用程序可伸缩性的极限。
await指令将在您的应用程序中生成一个工作流程,释放主线程。在长时间运行操作完成后,新任务将在线程池中排队,自动让您恢复应用程序。以这种方式释放和回收线程将使当前逻辑线程的数量保持在最低水平,从而防止饥饿和线程之间的更多上下文切换。
同样在.NET 4.5中,新算法控制线程池内新线程创建的成本/收益,在趋势增加时保持性能增加和上下文切换之间的合理关系。如果你已经没有这样做,那么你可以获得额外的好处。
因此,第一步是识别长时间运行的操作,然后使它们异步。
您可以通过将当前逻辑线程的#与其他计数器(数据库客户端连接,磁盘IO读取等)相关联来验证这一点。如果第一次增加,当其他人增加时,你可能会确定这是问题所在。还要检查操作需要多长时间。 100毫秒是一个很好的衡量标准,说你的操作在一般意义上是长期运行。
希望得到这个帮助。