记一次 .NET某MES自动化桌面程序 卡死分析

这篇具有很好参考价值的文章主要介绍了记一次 .NET某MES自动化桌面程序 卡死分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:背景

1. 讲故事

前些天有位朋友在微信上找到我,说他们的客户端程序卡死了,让我帮忙看下是什么原因导致的?dump也拿到了手,既然有了dump就开始正式分析吧。

二:WinDbg 分析

1. 什么导致的卡死

客户端的程序卡死比较好找原因,入手点就是主线程,看下它此时正在做什么,可以用 k 命令。


0:000> k
 # ChildEBP RetAddr      
00 003cdf7c 74c115ce     ntdll!NtWaitForSingleObject+0x15
01 003cdf7c 756e1194     KERNELBASE!WaitForSingleObjectEx+0x98
02 003cdf94 6f573bea     kernel32!WaitForSingleObjectExImplementation+0x75
03 003cdfc4 6f573c31     clr!CLREventWaitHelper2+0x33
04 003ce014 6f573bb6     clr!CLREventWaitHelper+0x2a
05 003ce04c 6f57c8be     clr!CLREventBase::WaitEx+0x152
06 003ce060 6f5764a9     clr!WKS::GCHeap::WaitUntilGCComplete+0x34
07 003ce0b0 6f583cf4     clr!Thread::RareDisablePreemptiveGC+0x231
08 003ce134 6a87a767     clr!JIT_RareDisableHelper+0x24
09 003ce16c 6a87472b     System_Drawing_ni+0x4a767
0a 003ce17c 0846b372     System_Drawing_ni!System.Drawing.Graphics.Clear+0x1b
...

从卦中信息看,代码正在托管层做Graphics,突然程序触发了GC,因为STW的原因,clr需要使用SuspendRuntime把主线程导入到 WaitUntilGCComplete 进行等待,有了这些信息之后,接下来就是寻找为什么会触发GC。

2. 为什么会触发 GC

要找到GC触发原因,首先要找哪一个线程触发了GC,这个可以用 !t 看下托管线程列表中的 GC 字样,输出如下:


0:000> !t
ThreadCount:      48
UnstartedThread:  0
BackgroundThread: 35
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
  48   42  ee8 0ee39f60   1029220 Cooperative 00000000:00000000 0076c700 3     MTA (GC) (Threadpool Worker) 
  ...

0:048> k 10
 # ChildEBP RetAddr      
00 4775c9e8 6f57d24e     clr!WKS::gc_heap::mark_object_simple1+0x8a
01 4775ca14 6f57bf72     clr!WKS::gc_heap::mark_object_simple+0x22b
02 4775ca34 6f5774b2     clr!WKS::GCHeap::Promote+0xaa
03 4775ca4c 6f57809c     clr!GcEnumObject+0x37
04 4775cdbc 6f5777cb     clr!EECodeManager::EnumGcRefs+0x854
05 4775ce10 6f5723b9     clr!GcStackCrawlCallBack+0x167
06 4775d0dc 6f5724bf     clr!Thread::StackWalkFramesEx+0x92
07 4775d410 6f57743b     clr!Thread::StackWalkFrames+0x9d
08 4775d448 6f57ba0e     clr!GCToEEInterface::GcScanRoots+0x108
09 4775d4a8 6f5792db     clr!WKS::gc_heap::mark_phase+0x18a
0a 4775d4d0 6f57966f     clr!WKS::gc_heap::gc1+0xda
0b 4775d508 6f57978c     clr!WKS::gc_heap::garbage_collect+0x447
0c 4775d530 6f70b767     clr!WKS::GCHeap::GarbageCollectGeneration+0x1f6
0d 4775d590 6f70b7a3     clr!WKS::gc_heap::trigger_ephemeral_gc+0x1e
0e 4775d590 6f575f6f     clr!WKS::gc_heap::allocate_small+0x270
0f 4775d5bc 6f575fca     clr!WKS::gc_heap::try_allocate_more_space+0x17c
...

从卦中可以看到当前 48 号线程触发了GC,并且是处于三阶段中的标记阶段,接下来需要观察下到底触发的是哪一代GC,可以用 dt 观察下 setting 全局变量即可。


0:048> x clr!*settings*
...
6fbd4bd8          clr!WKS::gc_heap::settings = <no type information>
6fbd7538          clr!SVR::gc_heap::settings = <no type information>
...

0:048> dp clr!WKS::gc_heap::settings
6fbd4bd8  00002ce4 00000002 00000001 00000001
6fbd4be8  00000000 00000000 00000000 00000000
6fbd4bf8  00000001 00000000 00000000 00000000
6fbd4c08  00000000 00000000 00000005 00000001
6fbd4c18  00000000 00000000 00000000 00000001
...

从卦中的 +0x4 偏移可以看到当前触发的是 FullGC,从 +0x38 可以看到GC的触发原因是 reason_oos_soh = 5,有经验的朋友看到这里应该就知道是什么原因了。

3. 为什么会触发FullGC

相信大家都知道FullGC 有一个 STW 的概念,既然有STW自然就会让程序卡死,回过头来说一下经验在哪里,对,就是这个指针的长度,很显然这个程序是 32bit 的,所以很大概率程序是 32bit 部署,会受到 2G 虚拟地址的限制,因为可用内存不足导致高频的触发 FullGC,可以用 !address -summary 去验证一下。


0:048> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown>                               955          6029f000 (   1.503 GB)  81.21%   75.13%
Image                                  1251          10105000 ( 257.020 MB)  13.57%   12.55%
Free                                    326           995d000 ( 153.363 MB)            7.49%
Stack                                   165           34c0000 (  52.750 MB)   2.78%    2.58%
Heap                                    137           2db0000 (  45.688 MB)   2.41%    2.23%
Other                                    12             47000 ( 284.000 kB)   0.01%    0.01%
TEB                                      55             37000 ( 220.000 kB)   0.01%    0.01%
PEB                                       1              1000 (   4.000 kB)   0.00%    0.00%
...
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT                             2152          66fc7000 (   1.609 GB)  86.97%   80.46%
MEM_RESERVE                             424           f6cc000 ( 246.797 MB)  13.03%   12.05%
MEM_FREE                                326           995d000 ( 153.363 MB)            7.49%
...

从卦中可以看到,当前程序吃了1.6G的虚拟地址,占全量的 80% ,这样情况按理说程序会抛 OutOfMemoryException 异常,在 !t 中也得到了验证。


0:048> !t
ThreadCount:      48
UnstartedThread:  0
BackgroundThread: 35
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
...
  33   39 10c8 0ee3dec0   1029220 Preemptive  00000000:00000000 0076c700 0     MTA (Threadpool Worker) System.OutOfMemoryException 32614444 (nested exceptions)
  ...
  46   44  89c 0ee3c458   1029220 Preemptive  00000000:00000000 0076c700 1     MTA (Threadpool Worker) System.OutOfMemoryException 32605d34 (nested exceptions)
  ...

接下来的问题是谁吃掉了 1.6G 的内存,总有地方会吃,可以使用 !eeheap -gc 观察下托管堆。


0:048> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x32632d50
generation 1 starts at 0x3262534c
generation 2 starts at 0x03291000
ephemeral segment allocation context: (0x3265ffb0, 0x3265ffbc)
 segment     begin  allocated      size
03290000  03291000  0428fee4  0xffeee4(16772836)
06c60000  06c61000  07c5ffc4  0xffefc4(16773060)
...
7d210000  7d211000  7e20ffac  0xffefac(16773036)
31660000  31661000  3265ffb0  0xffefb0(16773040)
Large object heap starts at 0x04291000
 segment     begin  allocated      size
04290000  04291000  0450fa78  0x27ea78(2615928)
53390000  53391000  54391020  0x1000020(16777248)
Total Size:              Size: 0x4622fd30 (1176698160) bytes.
------------------------------
GC Heap Size:    Size: 0x4622fd30 (1176698160) bytes.

从卦中看应该就是托管堆吃掉了,接下来就是看下托管堆中哪一类对象最多,最终找到了一个大集合,命令输出如下:


0:048> !gcroot 4c0507c0
Thread 89c:
    471bd450 07f76405 IBatisNet.DataMapper.MappedStatements.MappedStatement.RunQueryForList[[System.__Canon, mscorlib]](IBatisNet.DataMapper.Scope.RequestScope, IBatisNet.DataMapper.ISqlMapSession, System.Object, System.Collections.Generic.IList`1<System.__Canon>, IBatisNet.DataMapper.RowDelegate`1<System.__Canon>)
        ebp+90: 471be6c4
            ->  32c2ea50 System.Collections.Generic.List`1[[xxx.Model]]
            ->  53391010 xxxRMT[]
            ->  4c0507c0 xxxMT

0:048> !do 32c2ea50
Name:        System.Collections.Generic.List`1[[xxx, xxx]]
MethodTable: 095f1b58
EEClass:     6e246b4c
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
6e67ca34  4001886        4     System.__Canon[]  0 instance 53391010 _items
6e66f2d8  4001887        c         System.Int32  1 instance  3011824 _size
6e66f2d8  4001888       10         System.Int32  1 instance  3011824 _version
6e66d824  4001889        8        System.Object  0 instance 00000000 _syncRoot
6e67ca34  400188a        4     System.__Canon[]  0   static  <no information>

从卦中看当前的List有length=3011824,并且还被 89c 线程持有,最终通过代码找到了是某种查询下导致的大SQL引发。

三:总结

这次程序卡死还是挺有意思的,表象是主线程被GC卡住,实则是大SQL导致虚拟地址不足,分享出来让大家少踩坑吧!文章来源地址https://www.toymoban.com/news/detail-793528.html

记一次 .NET某MES自动化桌面程序 卡死分析

到了这里,关于记一次 .NET某MES自动化桌面程序 卡死分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.cnblogs.com/huangxincheng/Undeclared/17966932

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • windows桌面应用程序UI自动化工具

    WinApp(Windows APP)是运行在Windows操作系统上的应用程序,通常会提供一个可视的界面,用于和用户交互。 例如运行在Windows系统上的Microsoft Office、PyCharm、Visual Studio Code、Chrome,都属于WinApp。常见的WinApp,其扩展名基本都是*.exe,运行后也都会有一个漂亮、易用的UI界面,下面

    2024年02月11日
    浏览(11)
  • python控制Windows桌面程序自动化模块uiautomation

    github仓库地址:GitHub - yinkaisheng/Python-UIAutomation-for-Windows: (Donot use 3.7.6,3.8.1):snake:Python 3 wrapper of Microsoft UIAutomation. Support UIAutomation for MFC, WindowsForm, WPF, Modern UI(Metro UI), Qt, IE, Firefox, Chrome ...   uiautomation封装了微软UIAutomation API,支持自动化Win32,MFC,WPF,Modern UI(Metro UI), Qt, IE, F

    2024年02月04日
    浏览(8)
  • .NET MES桌面程序卡死分析

    1. 讲故事 客户端程序卡死是什么原因导致的?dump也拿到了手,既然有了dump就开始正式分析吧。 1. 什么导致的卡死 客户端的程序卡死比较好找原因,入手点就是主线程,看下它此时正在做什么,可以用  k  命令。 从卦中信息看,代码正在托管层做Graphics,突然程序触发了

    2024年01月22日
    浏览(16)
  • 记一次 某智能制造MES系统CPU 爆高分析

    前段时间有位朋友找到我,说他 docker 中的web服务深夜cpu被打满,让我帮忙看一下,很多朋友问docker中怎么抓dump,我一般都推荐使用 procdump 这款自动化工具,谁用谁知道,有了 dump 之后,接下来就是分析了。 有很多朋友问 linux 上的dump可以用 windbg 分析吗?这里统一回复下,

    2024年02月04日
    浏览(14)
  • 记一次 .NET 某餐饮小程序 内存暴涨分析

    前些天有位朋友找到我,说他的程序内存异常高,用 vs诊断工具 加载时间又太久,让我帮忙看一下到底咋回事,截图如下: 确实,如果dump文件超过 10G 之后,市面上那些可视化工具分析起来会让你崩溃的,除了时间久之外这些工具大多也不是用懒加载的方式,比如 dotmemory

    2024年02月08日
    浏览(11)
  • 记一次.Net Core程序启动失败的排查过程

    阅文时长 | 2分钟 字数统计 | 3212字符 主要内容 | 1、引言背景 2、排查.NetCore启动失败详细过程 3、声明与参考资料 『记一次.Net Core程序启动失败的排查过程』 编写人 | SCscHero 编写时间 | 2021/12/23 PM2:6 文章类型 | 系列 完成度 | 已完成 座右铭 每一个伟大的事业,都有一个微不足

    2024年02月05日
    浏览(14)
  • 记一次 .NET某工控 宇宙射线 导致程序崩溃分析

    为什么要提 宇宙射线 , 太阳耀斑 导致的程序崩溃呢?主要是昨天在知乎上看了这篇文章:莫非我遇到了传说中的bug? ,由于 rip 中的0x41变成了0x61出现了bit位翻转导致程序崩溃,截图如下: 下面的评论大多是说由于 宇宙射线 ,这个太玄乎了,说实话看到这个 传说bug 的提法

    2024年02月04日
    浏览(8)
  • 【一次关于webUI自动化测试的练习】

    IDEA工具:pycharm(社区版即可) Python3.9 Webdriver.exe文件 Chrome浏览器 注意: 需要将Webdriver.exe文件放到本地python的lib文件夹下,或者在代码中指定驱动的路径,如:driver = webdriver.Chrome(executable_path=‘driver/chromedriver.exe’) Webdriver.exe的版本需要和浏览器版本一致,不一致则会报错

    2024年02月22日
    浏览(8)
  • appium桌面版本以及一些自动化测试方方封装

    标签(空格分隔): appium_desktop 一 appium_desktop_v1.2.6 1.appium_desktop在github上最新下载地址:appium桌面版本地址 2.一路傻瓜式安装就好了: 3.然后点击搜索按钮(右上角) 三 inspector 1.元素定位探测器,在Desired Capabilitis下表格输入参数配置信息: 2.参数配置好之后可以保存下,连

    2023年04月13日
    浏览(11)
  • Appium: Windows系统桌面应用自动化测试(二)

    (1)下图是通过python脚本连接的不同应用 (2)应用一:有sessionId,说明会话正常,可通过句柄操作应用 (3)应用二:报500错误 (4)报错日志 HTTP/1.1 500 Internal Error Content-Length: 199 Content-Type: application/json {“status”:13,“value”:{“error”:“unknown error”,“message”:“Failed to l

    2024年02月11日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包