一:背景
1. 讲故事
前几天有位朋友在 B站 加到我,说他的程序出现了 线程数
爆高的问题,让我帮忙看一下怎么回事,截图如下:
说来也奇怪,这些天碰到了好几起关于线程数无缘无故的爆高,不过那几个问题比这一篇要复杂的多,主要涉及到非托管层面,分享这一篇的目的主要是它很有代表性,很有必要。
闲话不多说,既然线程数爆高,那就上 windbg 说话。
二:WinDbg 分析
1. 线程数真的高吗
既然说线程数高,那到底有多少呢? 我们可以用 !t
命令看一下。
0:000> !t
ThreadCount: 109
UnstartedThread: 0
BackgroundThread: 104
PendingThread: 0
DeadThread: 1
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 2970 00581020 26020 Preemptive 0294AE60:00000000 0057a5f0 0 STA
2 2 1d2c 00590670 2b220 Preemptive 00000000:00000000 0057a5f0 0 MTA (Finalizer)
5 4 3388 0063a9b8 102a220 Preemptive 00000000:00000000 0057a5f0 0 MTA (Threadpool Worker)
6 5 265c 0063b458 1020220 Preemptive 00000000:00000000 0057a5f0 0 Ukn (Threadpool Worker)
7 7 3370 07100fa8 202b220 Preemptive 00000000:00000000 0057a5f0 0 MTA
...
113 41 4af4 0a85a490 8029220 Preemptive 0294F918:00000000 0057a5f0 0 MTA (Threadpool Completion Port)
114 75 4b9c 0a83d818 8029220 Preemptive 00000000:00000000 0057a5f0 0 MTA (Threadpool Completion Port)
115 76 4ba0 0a83d2d0 8029220 Preemptive 02B53AC4:00000000 0057a5f0 0 MTA (Threadpool Completion Port)
从卦象看,当前有 115
个托管线程,从主线程的 STA
模式看 应该是一个 WinForm/WPF
程序,桌面程序这个线程数说多也不多,说少也不少,下一步的思路就是看下这些线程都在做什么。
2. 这些线程都在做什么
要探究每个线程都在做什么,可以用 ~*e !clrstack
调出所有线程栈,然后仔细耐心的观察这些线程。
0:000> ~*e !clrstack
OS Thread Id: 0x488c (109)
Child SP IP Call Site
114de760 7704018d [GCFrame: 114de760]
114de90c 7704018d [GCFrame: 114de90c]
114de8bc 7704018d [HelperMethodFrame: 114de8bc] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
114de94c 6dfe2767 System.Threading.Monitor.Enter(System.Object, Boolean ByRef)
114de95c 056107e3 CSRedis.Internal.IO.RedisIO.Write(Byte[])
114de998 05cb338c CSRedis.Internal.RedisConnector.Write(CSRedis.RedisCommand)
114de9dc 05cb32fc CSRedis.Internal.RedisListener1[[System.__Canon, mscorlib]].Write[[System.__Canon, mscorlib]](CSRedis.RedisCommand
1)
114de9f0 05cb3263 CSRedis.Internal.SubscriptionListener.Send(CSRedis.Internal.Commands.RedisSubscription)
114dea0c 050c4ffd CSRedis.RedisClient.Unsubscribe(System.String[])
114dea24 050c01e3 CSRedis.CSRedisClient+SubscribeObject+c__DisplayClass13_0.b__1(System.Object)
114deab4 6e026471 System.Threading.TimerQueueTimer.CallCallbackInContext(System.Object)
114deab8 6dfe2925 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
114deb24 6dfe2836 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
114deb38 6e026377 System.Threading.TimerQueueTimer.CallCallback()
114deb6c 6e0261fe System.Threading.TimerQueueTimer.Fire()
114debac 6e02612f System.Threading.TimerQueue.FireNextTimers()
114debec 6e025ff1 System.Threading.TimerQueue.AppDomainTimerCallback()
114dee10 6f38eaf6 [DebuggerU2MCatchHandlerFrame: 114dee10]
...
从卦象看,线程特征非常明显,有 86
个线程卡在 Monitor.ReliableEnter
处,它就是我们C#中的 监视锁 ,既然是监视锁,那就好办了,查看它的 同步块表
,看看谁在 lock 里赖着不出来导致其他线程等待,使用 windbg 的 !syncblk
命令。
`c#
0:000> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
72 005ef1f0 87 1 07176838 12c8 13 028374e4 System.Object
75 005efd1c 87 1 07176d80 32c0 14 028368ec System.Object
Original: https://www.cnblogs.com/huangxincheng/p/16443889.html
Author: 一线码农
Title: 记一次 .NET 某工控数据采集平台 线程数 爆高分析
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541836/
转载文章受原作者版权保护。转载请注明原作者出处!