一:背景

1. 讲故事

前段时间有位朋友微信上找到我,说它的程序出现了卡死,让我帮忙看下是怎么回事? 说来也奇怪,那段时间求助卡死类的dump特别多,被迫训练了一下对这类问题的洞察力 ,再次声明一下,我分析 dump 是免费的,没有某软高额的分析费用,你要问我图什么,图技术的精进。

回到正题,卡死类的问题分析入口点在于主线程此时在做什么,导致它不能处理自己的任务队列的原因是各种各样的,接下来上 windbg 分析一下。

二:WinDbg 分析

1. 主线程此时在做什么

看主线程很简单,直接一个 k 命令搞定。


0:000> k
# ChildEBP RetAddr
00 00f3ec2c 74ef6439 ntdll!NtWaitForSingleObject+0xc
01 00f3ec2c 70293370 KERNELBASE!WaitForSingleObjectEx+0x99
02 00f3ec5c 702933cc clr!CLREventWaitHelper2+0x33
03 00f3ecac 70293319 clr!CLREventWaitHelper+0x2a
04 00f3ece4 7037bbcf clr!CLREventBase::WaitEx+0x14b
05 00f3ecfc 70374f08 clr!WKS::GCHeap::WaitUntilGCComplete+0x35
06 00f3ed44 7032c2a2 clr!Thread::RareDisablePreemptiveGC+0x20b
07 00f3edc8 6d453712 clr!JIT_RareDisableHelper+0x22
08 00f3ee4c 6d4530d1 System_Windows_Forms_ni!System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)$##600550A+0x48e
09 00f3eea0 6d452f23 System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)$##6005539+0x175
0a 00f3eecc 6d42b83d System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)$##6005538+0x4f
0b 00f3eee4 02d90c83 System_Windows_Forms_ni!System.Windows.Forms.Application.Run(System.Windows.Forms.Form)$##60005FA+0x35
...

从卦上信息看,主线程正在等待(WaitUntilGCComplete) GC 处理完成,接下来看下是哪一个线程触发了 GC 操作,并看下它正在 GC 三阶段的哪一步?


0:000> !t
ThreadCount: 33
UnstartedThread: 3
BackgroundThread: 29
PendingThread: 3
DeadThread: 0
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 17a0 0113ecd0 26020 Preemptive 00000000:00000000 01139490 0 STA
2 2 2074 0114e0e0 2b220 Preemptive 00000000:00000000 01139490 0 MTA (Finalizer)
5 3 27f4 011ddaa8 102a220 Preemptive 00000000:00000000 01139490 0 MTA (Threadpool Worker)
8 4 2568 05bf0b90 1029220 Cooperative 00000000:00000000 01139490 1 MTA (GC) (Threadpool Worker) 0:000> ~8s
eax=00000000 ebx=05bf0b90 ecx=00000000 edx=00000000 esi=00000000 edi=00000f6c
eip=77e5aa5c esp=098ce03c ebp=098ce0ac iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
ntdll!NtWaitForSingleObject+0xc:
77e5aa5c c20c00 ret 0Ch
0:008> k
# ChildEBP RetAddr
00 098ce0ac 74ef6439 ntdll!NtWaitForSingleObject+0xc
01 098ce0ac 70293370 KERNELBASE!WaitForSingleObjectEx+0x99
02 098ce0dc 702933cc clr!CLREventWaitHelper2+0x33
03 098ce12c 70293319 clr!CLREventWaitHelper+0x2a
04 098ce164 7029333b clr!CLREventBase::WaitEx+0x14b
05 098ce17c 7032a9b7 clr!CLREventBase::Wait+0x1a
06 098ce1fc 7032a9ef clr!`anonymous namespace'::CreateSuspendableThread+0x165
07 098ce378 704322bd clr!GCToEEInterface::CreateThread+0x15c
08 098ce3a8 704332e5 clr!WKS::gc_heap::prepare_bgc_thread+0x36
09 098ce3a8 70378585 clr!WKS::gc_heap::garbage_collect+0x215
0a 098ce3c8 7037868a clr!WKS::GCHeap::GarbageCollectGeneration+0x1bd
0b 098ce3ec 70378703 clr!WKS::gc_heap::trigger_gc_for_alloc+0x1f
0c 098ce424 70396f6a clr!WKS::gc_heap::try_allocate_more_space+0x152
0d 098ce46c 70397311 clr!WKS::gc_heap::allocate_large_object+0x51
0e 098ce478 702fde2d clr!WKS::GCHeap::AllocLHeap+0x11
0f 098ce494 7063f1af clr!AllocLHeap+0x4b
10 098ce4e8 7028f598 clr!FastAllocatePrimitiveArray+0xa7
11 098ce58c 0e2d3fb6 clr!JIT_NewArr1+0x126
12 098cf26c 6f1f1b5a 0xe2d3fb6
13 098cf274 6f188604 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext(System.Object)$##6006FCB+0x1a
...

从卦中的 clr!GCToEEInterface::CreateThread 方法看,如果你没有这方面的分析经验,或许你已经无能为力了,以我的经验来说,既然卡死,那这里的 CreateThread 自然无法创建成功,创建不成功的原因在于 进程加载锁 LdrpLoaderLock 被别人持有了,导致它获取不到这把锁而一直茫然等待。

2. 谁持有了加载锁

要想找到谁持有了加载锁,可以在 ntdll 中搜 LdrpLoaderLock 字段,接下来使用 x 命令搜索。


0:008> x ntdll!LdrpLoaderLock
77f053b8 ntdll!LdrpLoaderLock = <no type information>
0:008> !cs 77f053b8
-----------------------------------------
Critical section = 0x77f053b8 (ntdll!LdrpLoaderLock+0x0)
DebugInfo = 0x77f0573c
LOCKED
LockCount = 0x0
WaiterWoken = No
OwningThread = 0x00001314
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x04000000

从卦中的 OwningThread = 0x00001314 迹象看,当前是线程 1314 持有了加载锁,看样子是要一生一世的持有。。。。 难怪程序不卡死。。。。 接下来切到这个线程看看到底咋这么痴情?


0:043> ~~[1314]s
eax=00000000 ebx=0589f784 ecx=00000000 edx=00000000 esi=00000000 edi=0589f770
eip=77e5c6bc esp=0589f72c ebp=0589f748 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ntdll!NtWaitForAlertByThreadId+0xc:
77e5c6bc c20800 ret 8
0:043> kb
# ChildEBP RetAddr Args to Child
00 0589f748 77e1336b 0ad114e8 00000000 00000000 ntdll!NtWaitForAlertByThreadId+0xc
01 0589f748 77e50630 00000000 00000000 ffffffff ntdll!RtlpWaitOnAddressWithTimeout+0x33
02 0589f78c 77e13299 00000004 00000000 00000000 ntdll!RtlpWaitOnAddress+0xa5
03 0589f7c8 77e2ed76 00000000 0ad114e0 0ad114e4 ntdll!RtlpWaitOnCriticalSection+0xaf
04 0589f7f0 77e2ec99 0589f814 0ac5d1b4 0ad114e4 ntdll!RtlpEnterCriticalSectionContended+0xd6
05 0589f7f8 0ac5d1b4 0ad114e4 00000003 0ac50000 ntdll!RtlEnterCriticalSection+0x49
06 0589f814 0ac5a890 00001314 0acddd2a 0ac50000 fwlibe1!xxx+0x13e3
07 0589f83c 77e5a9f6 0ac50000 00000003 00000000 fwlibe1!xxx+0x290
...

从卦中看,当前是 fwlibe1 这个非托管dll 准备获取 临界区 时卡死,接下来可以用 !cs 把 临界区变量 给提取出来看看到底谁在持有这个 临界区变量。


0:043> !cs 0ad114e4
-----------------------------------------
Critical section = 0x0ad114e4 (fwlibe1!xxxx+0x3A1C2)
DebugInfo = 0x0ff43360
LOCKED
LockCount = 0x2
WaiterWoken = No
OwningThread = 0x00002378
RecursionCount = 0x1
LockSemaphore = 0xFFFFFFFF
SpinCount = 0x020007d0

从卦中可以清晰的看到,当前临界区变量被 2378 号线程持有,接下来切到这个线程看看到底啥情况。


0:043> ~~[2378]s
eax=00000036 ebx=00002378 ecx=00000400 edx=00000157 esi=0ad114fc edi=0ad114e4
eip=0ac5cf88 esp=0caddf18 ebp=0cade7fc iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
fwlibe1!xxx+0x11b7:
0ac5cf88 8d45f0 lea eax,[ebp-10h] 0:028> k
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0cade7fc 0ac5a8df fwlibe1!xxx+0x11b7
01 0cade938 0ac5abae fwlibe1!xxx+0x22
02 0cadea20 09417ccd fwlibe1!xxx+0x17
03 0cadebfc 09412c11 0x9417ccd
04 0caded2c 6f1f1b5a 0x9412c11
05 0caded34 6f188604 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext(System.Object)$##6006FCB+0x1a
... 0:028> !clrstack
OS Thread Id: 0x2378 (28)
Child SP IP Call Site
0cade9b4 0ac5cf88 [InlinedCallFrame: 0cade9b4]
0cade998 0941a0e9 *** WARNING: Unable to verify checksum for System.Data.ni.dll
DomainBoundILStubClass.IL_STUB_PInvoke(System.Object, UInt16, Int32, UInt16 ByRef)
0cade9b4 09417ccd [InlinedCallFrame: 0cade9b4] Focas.xxx(System.Object, UInt16, Int32, UInt16 ByRef)

从卦中看,托管层调用了 Focas.xxx 函数进入了 fwlibe1.dll ,最后有一句 WARNING: Stack unwind information not available. Following frames may be wrong. ,可能是展开有一定的问题,不过排查到这里,应该就是这个 Focas.xxx 的问题了。

3. 真相大白

接下来将我的排查结果跟朋友反馈了下,朋友排查下来说是最近改了这里面的连接方式所致,修改之后就搞定了。

三:总结

这个案例告诉我们:只要代码还能跑,就不要动它,它要是不动了,你得要做好动的准备。

记一次 .NET 某数控机床控制程序 卡死分析的更多相关文章

  1. 记一次 .NET 某药品仓储管理系统 卡死分析

    一:背景 1. 讲故事 这个月初,有位朋友wx上找到我,说他的api过一段时间后,就会出现只有请求,没有响应的情况,截图如下: 从朋友的描述中看样子程序是被什么东西卡住了,这种卡死的问题解决起来相对简 ...

  2. 记一次 .NET 某金融企业 WPF 程序卡死分析

    一:背景 1. 讲故事 前段时间遇到了一个难度比较高的 dump,经过几个小时的探索,终于给找出来了,在这里做一下整理,希望对大家有所帮助,对自己也是一个总结,好了,老规矩,上 WinDBG 说话. ...

  3. 远程监控显示brother数控机床数据

    最近几个月公司太忙了,到现在已经连续出差两个多月了. 这个项目这要做mes系统,涉及到产品在机床的加工过程监控,然后led看板显示产品进度. 这里的主角是日本的brother数控机床,服务器按照一定频 ...

  4. 记一次ORACLE的UNDO表空间爆满分析过程

    这篇文章是记录一次ORACLE数据库UNDO表空间爆满的分析过程,主要整理.梳理了同事分析的思路.具体过程如下所示: 早上收到一数据库服务器的UNDO表空间的告警邮件,最早一封是7:55发出的(监控作 ...

  5. 记java应用linux服务单个CPU使用率100%分析

    之前在做项目的过程中,项目完成后在linux服务器上做性能测试,当服务跑起来的时候发现cpu使用率很奇怪,java应用把单个cpu跑满了,其他cpu利用率0%. 刚开始遇到这问题的时候我第一时间反应使 ...

  6. 记一次vue长列表的内存性能分析和优化

    好久没写东西,博客又长草了,这段时间身心放松了好久,都没什么主题可以写了 上周接到一个需求,优化vue的一个长列表页面,忙活了很久也到尾声了,内存使用和卡顿都做了一点点优化,还算有点收获 写的有点啰嗦 ...

  7. 记一次:Windows的Socket编程学习和分析过程

    Socket编程依赖于:WS2_32.dll --- 服务端 --- .导入我们需要的函数 #incldue <windows.h> //#include<WinSock2.h> ...

  8. 记一次 .NET 医院CIS系统 内存溢出分析

    一:背景 1. 讲故事 前几天有位朋友加wx求助说他的程序最近总是出现内存溢出,很崩溃,如下图: 和这位朋友聊下来,发现他也是搞医疗的,哈哈,.NET 在医疗方面还是很有市场的,不过对于内存方面出的问 ...

  9. 记一次 .NET 车联网云端服务 CPU爆高分析

    一:背景 1. 讲故事 前几天有位朋友wx求助,它的程序CPU经常飙满,没找到原因,希望帮忙看一下. 这些天连续接到几个cpu爆高的dump,都看烦了,希望后面再来几个其他方面的dump,从沟通上看, ...

随机推荐

  1. Kubernetes-23:详解如何将CPU Manager做到游刃有余

    k8s中为什么要用CPU Manager? 默认情况下,kubelet 使用CFS配额来执行 Pod 的 CPU 约束.Kubernetes的Node节点会运行多个Pod,其中会有部分的Pod属于CP ...

  2. orcal恢复delete误删除的数据

    orcal的删除有3种:delete.truncate.drop. delete可以手动提交和回滚,且可以使用where:而truncate.drop执行即对表数据进行了修改,且不能使用where. ...

  3. 编程技巧│提高 Javascript 代码效率的技巧

    目录 一.变量声明 二.三元运算符 三.解构赋值 四.解构交换 五.箭头函数 六.字符串模版 七.多值匹配 八.ES6对象简写 九.字符串转数字 十.次方相乘 十一.数组合并 十二.查找数组最大值最小 ...

  4. Kali MSF漏洞利用

    一.前言 漏洞利用是获得系统控制权限的重要途经.用户从目标系统中找到容易攻击的漏洞,然后利用该漏洞获取权限,从而实现对目标系统的控制. 二.Metasploitable Metasploitable是 ...

  5. 搭建uipath

    我对windows也不太熟,也是第一次安装Uipath Orchestrator,希望有问题指出一起交流,可以留言,Uipath中文qq交流群:4656303241. 下载镜像 windows ser ...

  6. NC23036 华华听月月唱歌

    NC23036 华华听月月唱歌 题目 题目描述 月月唱歌超级好听的说!华华听说月月在某个网站发布了自己唱的歌曲,于是把完整的歌曲下载到了U盘里.然而华华不小心把U盘摔了一下,里面的文件摔碎了.月月的歌 ...

  7. NC14247 Xorto

    NC14247 Xorto 题目 题目描述 给定一个长度为 \(n\) 的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为 \(0\) . 输入描述 第一行一个数 \(n\) 表示 ...

  8. 基于InsightFace的高精度人脸识别,可直接对标虹软

    一.InsightFace简介 InsightFace 是一个 2D/3D 人脸分析项目.InsightFace 的代码是在 MIT 许可下发布的. 对于 acadmic 和商业用途没有限制. 包含注 ...

  9. springboot集成swagger2报Illegal DefaultValue null for parameter type integer

    springboot集成swagger2,实体类中有int类型,会报" Illegal DefaultValue null for parameter type integer"的 ...

  10. centos 7系统安装

    1.打开VMware软件,点击创建虚拟机,默认选择,点击下一步 2.选择稍后安装,点击下一步 3.在Linux系统中选择CentOS 7 64位,点击下一步 4.选择好安装位置后,点击下一步 5.选择 ...