那个网站做玉石最专业,网站网站开发需要多少钱,厦门门户网站建设,php手机网站建设一#xff1a;背景
1. 讲故事
前几天有位朋友找到我#xff0c;说他们的API服务程序跑着跑着CPU满了降不下去#xff0c;让我帮忙看下怎么回事#xff0c;现在貌似民间只有我一个人专注dump分析#xff0c;还是申明一下我dump分析是免费的#xff0c;如果想学习.NET高级…一背景
1. 讲故事
前几天有位朋友找到我说他们的API服务程序跑着跑着CPU满了降不下去让我帮忙看下怎么回事现在貌似民间只有我一个人专注dump分析还是申明一下我dump分析是免费的如果想学习.NET高级调试的分析技术可以来我的训练营看看话不多说dump分析走起
二WinDbg分析
1. CPU 真的爆高吗
昨天录了一个小视频大意就是作为分析师不要过分的相信客户说的话他们往往会把你带偏你要有自己的分析思路和前进方向所以需要以数据说话首先用 !tp 观察下线程池。 0:030 !tp
CPU utilization: 60%
Worker Thread: Total: 18 Running: 3 Idle: 15 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 0
--------------------------------------
Number of Timers: 3
--------------------------------------
Completion Port Thread:Total: 3 Free: 1 MaxFree: 8 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 4
从卦中可以看到当前的 CPU60%这个值说高也不高说低也不低接下来观察下这台机器的cpu核心数可以用 !cpuid 观察。 0:030 !cpuid
CP F/M/S Manufacturer MHz0 6,63,2 unavailable 22951 6,63,2 unavailable 22952 6,63,2 unavailable 22953 6,63,2 unavailable 2295
真的是无语做游戏的不都是有钱的主难道都在降本增效吗既然到了 60%说明有两个线程估计脱轨了接下来就需要观察下那2个托轨线程都在做什么
2. 脱轨线程在干嘛
要想观察每个线程都在做什么可以使用 ~*e !clrstack 命令即可。 0:030 ~*e !clrstack
OS Thread Id: 0x3eec (30)Child SP IP Call Site
0000001f8fbad610 00007ffd958535c3 System.Collections.Generic.HashSet1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8fbad680 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8fbad6c0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8fbad700 00007ffd3d12b3da xxx.CookieHelper.Read(System.String)
...
OS Thread Id: 0x5cf0 (31)Child SP IP Call Site
0000001f8d27d330 00007ffd958535b8 System.Collections.Generic.HashSet1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8d27d3a0 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8d27d3e0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8d27d420 00007ffd3e2ab6da xxx.CookieHelper.Read(System.String)
...
仔细琢磨了一下卦象后发现有两个线程都停在 HashSet 上而且这个集合还是来自于底层的 System.Web对一般人来说这个是比较奇葩的现象但对于我这种有300分析经验的熟手来说一眼就看出来了什么问题对就是多线程操控 HashSet 导致的死循环接下来的问题是如何去验证呢毕竟空口无凭。。。
3. 真的死循环了吗
要想了解有没有真的死循环需要你对 HashSet 的底层有一个了解比如说 HashSet 挂链的时候在内部是如何组织的其实这个我在.NET高级训练营里面也做过讲解也做过演示接下来切到 31 号线程观察下它的 HashSet 结构。 0:031 !mdso
Thread 31:
Location Object Type
------------------------------------------------------------
RCX: 000000200054ffc0 System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]][]
RSI: 000000200054ff58 System.Collections.Generic.HashSet1[[System.String, mscorlib]]
...
0:031 !mdt 000000200054ff58
000000200054ff58 (System.Collections.Generic.HashSet1[[System.String, mscorlib]])m_buckets:000000200054ff98 (System.Int32[], Elements: 3)m_slots:000000200054ffc0 (System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]][], Elements: 3, ElementMT00007ffd95555230)m_count:0x0 (System.Int32)m_lastIndex:0x0 (System.Int32)m_freeList:0xffffffff (System.Int32)m_comparer:00000022003d3380 (System.OrdinalComparer)m_version:0x6 (System.Int32)m_siInfo:NULL (System.Runtime.Serialization.SerializationInfo)
...
0:031 !mdt -e:2 000000200054ffc0
000000200054ffc0 (System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]][], Elements: 3, ElementMT00007ffd95555230)
[0] (System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]]) VALTYPE (MT00007ffd95555230, ADDR000000200054ffd0)hashCode:0xffffffff (System.Int32)next:0x0 (System.Int32)value:NULL (System.__Canon)
[1] (System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]]) VALTYPE (MT00007ffd95555230, ADDR000000200054ffe0)hashCode:0x3eb5808c (System.Int32)next:0xffffffff (System.Int32)value:000000200054f8f0 (System.String) Length6, Stringxxx
[2] (System.Collections.Generic.HashSet1Slot[[System.String, mscorlib]]) VALTYPE (MT00007ffd95555230, ADDR000000200054fff0)hashCode:0x7e225883 (System.Int32)next:0x1 (System.Int32)value:000000200054fba0 (System.String) Length12, Stringxxx
熟悉 HashSet底层的朋友从上面的卦信息一眼就能看出问题对就是这个 next:0x0在hashset的挂链中最后一个节点永远是 -1如果是 0 的话就相当于指向数组的首元素最后就是无情死循环了知道了前因后果之后接下来就要寻找下到底是什么圣神代码。
4. 到底是什么奇葩代码
这个比较简单观察下线程栈的托管层代码然后看源码即可为了保护客户隐私我就多注释一点输出如下 0:031 !clrstack
OS Thread Id: 0x5cf0 (31)Child SP IP Call Site
0000001f8d27d330 00007ffd958535b8 System.Collections.Generic.HashSet1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8d27d3a0 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8d27d3e0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8d27d420 00007ffd3e2ab6da xxx.CookieHelper.Read(System.String)
...
虽然信息比较少但卦还是很明朗的客户写了一个 CookieHelper 封装了 Request.Cookies 操作那到底怎么封装的呢仔细阅读代码之后终于发现了截图如下 我去这代码还是挺奇葩的居然将 Cookies 给了静态变量静态变量可是一个进程小缓存呢水落石出之后改发也比较简单把 static 去掉即可。
三总结
这种将Request.Cookies赋给静态变量的奇葩操作其实蕴含着巨大的安全隐患会导致多个用户之间串cookie但以服务器自爆的方式来避免客户端串cookie真的是不幸中的万幸哈哈同时用bug去抑制另一个bug的神操作也真的是大自然的鬼斧神工