一:背景

1. 讲故事

前段时间微信上有位非调试训练营学员找到我,说他们的医疗软件有点问题,有时候卡了一会就好了,有时候卡了很久,让我帮忙看下怎么回事,我让这位朋友在卡的时候抓一个dump给我,我分析看看。

二:卡死分析

1. 为什么会卡死

对于窗体程序的卡死,主要就是看主线程此时正在做什么,使用 ~0s;k 命令即可,输出如下:


0:000> ~0s;k
PresentationCore_ni!string+0x1e6968:
00007ffb`f4407e60 250000e0ff and eax,0FFE00000h
# Child-SP RetAddr Call Site
00 0000005f`849fc7c0 00007ffb`f4407da7 PresentationCore_ni!`string'+0x1e6968
01 0000005f`849fc810 00007ffb`f43d1d5a PresentationCore_ni!System.Windows.ContextLayoutManager.LayoutQueue.Add+0x37
02 0000005f`849fc860 00007ffb`f2e5a4b8 PresentationCore_ni!System.Windows.UIElement.InvalidateMeasure+0xda
03 0000005f`849fc8b0 00007ffb`f2ead5bd PresentationFramework_ni!System.Windows.FrameworkElement.OnPropertyChanged+0x8b8
04 0000005f`849fcb10 00007ffc`1ae9c394 PresentationFramework_ni!System.Windows.Controls.TextBlock.OnPropertyChanged+0x5d
...
26 0000005f`849fe460 00007ffc`1ae9044f WindowsBase_ni!System.Windows.Threading.Dispatcher.ProcessQueue+0x1fd
27 0000005f`849fe4f0 00007ffc`1ae93314 WindowsBase_ni!System.Windows.Threading.Dispatcher.WndProcHook+0x6f
28 0000005f`849fe570 00007ffc`1ae93714 WindowsBase_ni!MS.Win32.HwndWrapper.WndProc+0xc4
29 0000005f`849fe600 00007ffc`1ae93d58 WindowsBase_ni!MS.Win32.HwndSubclass.DispatcherCallbackOperation+0x84
2a 0000005f`849fe650 00007ffc`1ae93c56 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall+0x68
2b 0000005f`849fe6c0 00007ffc`1ae91262 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen+0x36
2c 0000005f`849fe710 00007ffc`1ae93082 WindowsBase_ni!System.Windows.Threading.Dispatcher.LegacyInvokeImpl+0x172
2d 0000005f`849fe7b0 00007ffc`1b053b82 WindowsBase_ni!MS.Win32.HwndSubclass.SubclassWndProc+0x152
2e 0000005f`849fe8b0 00007ffc`2f0e224e WindowsBase_ni+0x323b82
2f 0000005f`849fe920 00007ffc`505ce7e8 clr!UMThunkStub+0x6e
30 0000005f`849fe9b0 00007ffc`505ce229 user32!UserCallWinProcCheckWow+0x2f8
31 0000005f`849feb40 00007ffc`1aeb4479 user32!DispatchMessageWorker+0x249
...
43 0000005f`849ffc60 00000000`00000000 ntdll!RtlUserThreadStart+0x21

从卦中的 ProcessQueue, TextBlock.OnPropertyChanged 等函数来看,当前主线程正在忙碌处理,如果你想看主线程的执行流细节,可以将dmp拖到vs中,让vs帮我们解读,拖进去后是不是一下子就清晰多了。。。截图如下:

接下来的问题是这玩意会导致UI的卡死吗? 经验上告诉我,这个概率不大,毕竟 PresentationCore.dll 中的代码固若金汤,那问题出在哪里呢?大概率就是窗体的Queue队列积压过多导致。

2. Queue队列积压过多吗

要想找到这个问题的答案,可以深挖调度类Dispatcher,使用 !dso xxx 到当前线程栈里去捞。


0:000> !dso
OS Thread Id: 0x34d0 (0)
RSP/REG Object Name
...
0000005F849FED20 0000020c4a784dc8 System.Windows.Threading.Dispatcher
... 0:000> !do 0000020c4a784dc8
Name: System.Windows.Threading.Dispatcher
MethodTable: 00007ffc1ad53e30
EEClass: 00007ffc1ad8a6f0
Size: 232(0xe8) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll
Fields:
MT Field Offset Type VT Attr Value Name
...
00007ffc1ad4caf8 4001284 a0 ...on, WindowsBase]] 0 instance 0000020c4a784f08 _queue
... 0:000> !do 0000020c4a784f08
Name: System.Windows.Threading.PriorityQueue`1[[System.Windows.Threading.DispatcherOperation, WindowsBase]]
MethodTable: 00007ffc1ad4caf8
EEClass: 00007ffc1adab1e8
Size: 56(0x38) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll
Fields:
MT Field Offset Type VT Attr Value Name
0000000000000000 4001240 8 0 instance 0000020c4a784f40 _priorityChains
0000000000000000 4001241 10 0 instance 0000020c4a785078 _cacheReusableChains
00007ffc1b18f340 4001242 18 ...Canon, mscorlib]] 0 instance 0000020c31b84d68 _head
00007ffc1b18f340 4001243 20 ...Canon, mscorlib]] 0 instance 0000020ce073ca68 _tail
00007ffc2b4d85a0 4001244 28 System.Int32 1 instance 889015 _count

这卦象很不吉利,UI 队列居然积压了高达 88w 的未处理任务,难怪这位朋友说软件卡死了,其实UI线程在忙碌的任务处理,看样子没个几天几夜搞不定哈。

接下来的问题是为什么会积压这么多,要想找到这个问题的答案,可以从 88w 的queue队列中抽选几个任务,看看大概都是些什么,展开上面的 _tail 节点即可。


0:000> !DumpObj /d 0000020ce073ca68
Name: System.Windows.Threading.PriorityItem`1[[System.Windows.Threading.DispatcherOperation, WindowsBase]]
MethodTable: 00007ffc1ad4e5e0
EEClass: 00007ffc1adb28a0
Size: 64(0x40) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll
Fields:
MT Field Offset Type VT Attr Value Name
00007ffc2b4da238 400123a 8 System.__Canon 0 instance 0000020ce073c898 _data
... 0:000> !DumpObj /d 0000020ce073c840
Name: System.Action
MethodTable: 00007ffc2b55aff0
EEClass: 00007ffc2b665440
Size: 64(0x40) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
MT Field Offset Type VT Attr Value Name
00007ffc2b4d5dd8 40002f3 8 System.Object 0 instance 0000020c4ba28050 _target
00007ffc2b4d5dd8 40002f4 10 System.Object 0 instance 0000000000000000 _methodBase
00007ffc2b5531f8 40002f5 18 System.IntPtr 1 instance 7ffbcfb85b10 _methodPtr
... 0:000> !U 7ffbcfb85b10
Unmanaged code
00007ffb`cfb85b10 e9db38e700 jmp 00007ffb`d09f93f0
00007ffb`cfb85b15 5f pop rdi
00007ffb`cfb85b16 61 ???
00007ffb`cfb85b17 0040dc add byte ptr [rax-24h],al
00007ffb`cfb85b1a c8cffb7f enter 0FBCFh,7Fh
00007ffb`cfb85b1e 0000 add byte ptr [rax],al
00007ffb`cfb85b20 e80bea555f call clr!PrecodeFixupThunk (00007ffc`2f0e4530)
00007ffb`cfb85b25 5e pop rsi
00007ffb`cfb85b26 0000 add byte ptr [rax],al
00007ffb`cfb85b28 68e1c8cffb push 0FFFFFFFFFBCFC8E1h 0:000> !U 00007ffb`d09f93f0
Normal JIT generated code
WpfApp.ViewModel.CalculatedIsocenterShiftViewModel.<UpdateLineGraph>b__93_0()
Begin 00007ffbd09f93f0, size f54
>>> 00007ffb`d09f93f0 55 push rbp
...

从卦中可以看到有一个 <UpdateLineGraph>b__93_0 方法,看样子这是一个匿名方法,接下来用 ilspy 打开观察源代码,截图如下:

从卦中的代码看,尼玛,这是兵家大忌哈。。。居然让UI线程做什么复杂的业务逻辑,这怎么不让 UI线程 累死。。。

为了佐证,可以使用 ~*e !clrstack 观察此时的各个线程栈,可以发现目前有两个线程正在通过 Dispatcher 给UI发通知并等待UI线程响应,截图如下:

到这里基本就真相大白了,这位朋友应该是高频的往UI打数据(画图),导致软件卡死。

三:总结

这次卡死事故是这位朋友犯了兵家大忌,UI线程只用来更新UI,不要将复杂的业务逻辑丢给UI去做。

记一次 .NET 某放射治疗光学定位软件 卡死分析的更多相关文章

  1. 记一次 .NET 某物管后台服务 卡死分析

    一:背景 1. 讲故事 这几个月经常被朋友问,为什么不更新这个系列了,哈哈,确实停了好久,主要还是打基础去了,分析 dump 的能力不在于会灵活使用 windbg,而是对底层知识有一个深厚的理解,比如 ...

  2. 记一次 .NET 某工控自动化控制系统 卡死分析

    一:背景 1. 讲故事 前段时间遇到了好几起关于窗体程序的 进程加载锁 引发的 程序卡死 和 线程暴涨 问题,这种 dump 分析难度较大,主要涉及到 Windows操作系统 和 C++ 的基础知识, ...

  3. 记一次 .NET 某企业OA后端服务 卡死分析

    一:背景 1.讲故事 前段时间有位朋友微信找到我,说他生产机器上的 Console 服务看起来像是卡死了,也不生成日志,对方也收不到我的httpclient请求,不知道程序出现什么情况了,特来寻求帮助 ...

  4. 记一次 .NET 某自动化集采软件 崩溃分析

    一:背景 1.讲故事 前段时间有位朋友找到我,说他的程序在客户的机器上跑着跑着会出现偶发卡死,然后就崩掉了,但在本地怎么也没复现,dump也抓到了,让我帮忙看下到底怎么回事,其实崩溃类的dump也有简 ...

  5. 记一次 .NET某医疗器械清洗系统 卡死分析

    一:背景 1. 讲故事 前段时间协助训练营里的一位朋友分析了一个程序卡死的问题,回过头来看这个案例比较经典,这篇稍微整理一下供后来者少踩坑吧. 二:WinDbg 分析 1. 为什么会卡死 因为是窗体程 ...

  6. 安卓虚拟定位软件Fake Location重大更新

    前段时间网上找安卓虚拟定位的软件,找了很久,大部分都是多开修改APP,或者是不可用的,最后在KUAN找到一个作者Lerist做的虚拟定位软件 Fake Location ,配合作者本人的一键解锁sys ...

  7. “深度评测官”——记2020BUAA软工软件案例分析作业

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 个人博客作业-软件案例分析 我在这个课程的目标是 完成一次完整的软件开发经历并以博客的方式记录开发 ...

  8. 记一次httpclient Connection reset问题定位

    问题:某业务系统在运行一段时间后,某个API一定概率偶现Connection reset现象. 问题定位: 首先想到的是要本地复现出这个问题,但一直复现不出来. 1.根据线上问题相关日志判断应该是有部 ...

  9. 记一次常规的Mysql数据库访问的时间分析

    背景:记一次常规的数据访问的时间分析(插入操作) 1. TCP三次握手 SYN ---> <--- SYN,ACK ACK ---> 花费时间: 386.718-385.784=0. ...

  10. 记一次WMS的系统改造(1)-分析问题

    海外落地中的困境 目前面临主要的问题是"人",仓储系统主要辅助仓储人员进行生产,所以人变了其实一切就都已经变了,系统在海外面临最大的问题就是人变了. 这套软件是在国内的运营体系 ...

随机推荐

  1. kubernetes网络组件calico详解

    一.Calico介绍 Calico是一种容器之间互通的网络方案,在虚拟化平台中,比如OpenStack.Docker等都需要实现workloads之间互连,但同时也需要对容器做隔离控制,就像在Inte ...

  2. Arduino从零开始的高手之路0——引言:Arduino是世界上最好的开发板!

    开篇先比比: 虽然我们的老会长一直强调Arduino是个很菜的东西,但是的确是嵌入式入门的不二法宝啊. 现在其实我已经学了stm32了,arduino自认为比较精通了,但是其实实践上手的机会还是很少 ...

  3. 无监控,不运维!深入浅出介绍ChengYing监控设计和使用

    监控系统俗称「第三只眼」,几乎是我们每天都会打交道的系统,它也一直是IT系统中的核心组成部分,负责问题的发现以及辅助性的定位. ChengYing作为一站式全自动化全生命周期大数据平台运维管家,自然也 ...

  4. MySQL核心知识学习之路(4)

    作为一个后端工程师,想必没有人没用过数据库,跟我一起复习一下MySQL吧,本文是我学习<MySQL实战45讲>的总结笔记的第四篇,总结了MySQL的锁相关知识. 上一篇:MySQL核心知识 ...

  5. MySQL查询执行顺序:一张图看懂SQL是如何工作的

    MySQL查询执行顺序:一张图看懂SQL是如何工作的 你写的SQL语句为什么这么慢?为什么有时候加了索引还是不走?为什么GROUP BY要放在WHERE后面?这些问题的答案都藏在SQL的执行顺序里! ...

  6. 可配置Modbus网关 嵌入式设备联网解决方案

    ​ 1.概述 可配置Modbus网关可以预先配置Modbus RTU端的设备的地址.功能码和寄存器列表,并存储到网关内部.网关会自动采集这些配置的RTU设备的数据,然后映射到连续的Modbus TCP ...

  7. 酒馆SillyTavern安装使用,打造专属AI聊天

    一.什么是 SillyTavern? 这是一个"让AI陪你角色扮演聊天"的神器. 它是一个 前端聊天界面,可以接入 ChatGPT.Claude.geminì,甚至自己本地跑的模型 ...

  8. openWrt安装三方插件

    前言 openWrt是一款开源的路由器系统,其最大的优点就是 支持第三方扩展插件. 新增的插件基本都会在左侧的服务菜单中展现,通过此入口就可以使用插件功能. 大部分openWrt固件都帮你装好了ope ...

  9. linux centos配置环境变量

    前言 在centos上配置环境变量,有两种情况:分别是系统级别的,和用户级别的. 用户级别的 只对当前用户生效,切换至其他linux用户则无效. 系统级别的则对所有用户都生效(建议). 用户级别 .b ...

  10. 【HDU 1505】 City Game 单调栈

    传送门 HDU-1505 题意:找到矩阵中的最大子矩阵(有些点为障碍物). 思路: 看到网上清一色的dp,我就写一下这个题的单调栈做法.其实这个题和HDU-1506这个题是基本一样的. 1.在1506 ...