記一次 .NET 某數控機床控制程序 卡死分析

一:背景

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:???noLock??ID?OSID?ThreadOBJ????State?GC?Mode?????GC?Alloc?Context??Domain???Count?Apt?Exception0????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. 真相大白

接下來將我的排查結果跟朋友反饋了下,朋友排查下來說是最近改了這里面的連接方式所致,修改之后就搞定了。

7778c76af3b044b6710778542edd437f.png

三:總結

這個案例告訴我們:只要代碼還能跑,就不要動它,它要是不動了,你得要做好動的準備。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282961.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282961.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282961.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TODO-MVP-Loaders源碼體驗

大家好&#xff0c;我是蒼王。以下是我這個系列的相關文章&#xff0c;有興趣可以參考一下&#xff0c;可以給個喜歡或者關注我的文章。[Android]如何做一個崩潰率少于千分之三噶應用app--章節列表相信有關注我的人&#xff0c;都會看過我上一編介紹的Todo-mvp源碼體驗&#xf…

.NET Framework 4.8預覽

雖然人們的大多數關注點都在.NET Core上&#xff0c;但經典的.NET Framework仍然在開發中。.NET 4.8的“早期訪問”預覽版表明了微軟最關心的領域包括高DIP、可訪問性和并發性。\\.NET 4.8預計將于2019年發布。目前的預期是&#xff0c;它將在稍后的Windows 10 build 1607上運行…

java項目商品的排名,分析了5萬個開源項目,得出的排名前16的Java工具類

原文:https://www.jianshu.com/p/9e937d178203在Java中&#xff0c;工具類定義了一組公共方法&#xff0c;這篇文章將介紹Java中使用最頻繁及最通用的Java工具類。以下工具類、方法按使用流行度排名&#xff0c;參考數據來源于Github上隨機選取的5萬個開源項目源碼。一. org.ap…

IDEA遠程調試

參考鏈接&#xff1a;http://www.cnblogs.com/wy2325/p/5600232.html 調試端口是catlina.sh中的 JAVA_OPTS-agentlib:jdwptransportdt_socket,servery,suspendn,address5023 -Xms1024m -Xmx3072m -XX:MaxNewSize128m #!/bin/sh 配置的端口&#xff0c;是address ******&#…

ASP.NETCoreWeb開發之OptionsPattern

這節我們來講一下&#xff0c;在ASP.NET Core Web開發中&#xff0c;讀取配置文件信息的新方式&#xff1a;Options。前言 /Options在ASP.NET Web框架中&#xff0c;我們讀取配置文件中的數據&#xff0c;在不使用第三方框架的情況下&#xff0c;可能需要通過ConfigurationMana…

SpringMVC執行流程圖

2019獨角獸企業重金招聘Python工程師標準>>> 轉載于:https://my.oschina.net/u/2607324/blog/827946

CC框架實踐(1):實現登錄成功再進入目標界面功能

在掘金上看到這篇文章&#xff1a;android 關于先登錄成功后再進入目標界面的思考,作者對實現登錄成功后再跳轉到目標界面功能作了比較詳細的分析&#xff0c;對比了一些已有的實現方案并指出存在的問題。最終&#xff0c;作者實現了一個可同時添加多個條件判斷攔截的方案&…

yum search php7,yum install php7 in centos6

如果有安裝的PHP包&#xff0c;先刪除他們yum list installed | grep phpyum remove php.x86_64 php-cli.x86_64 php-common.x86_64 php-gd.x86_64 php-ldap.x86_64 php-mbstring.x86_64 php-mcrypt.x86_64 php-mysql.x86_64 php-pdo.x86_64yum 安裝我們需要的軟件1.安裝epel軟…

CentOS 7系統安裝配置圖解教程

操作系統&#xff1a;CentOS 7.3 備注&#xff1a; CentOS 7.x系列只有64位系統&#xff0c;沒有32位。生產服務器建議安裝CentOS-7-x86_64-Minimal-1611.iso版本 一、安裝CentOS 7.3 成功引導系統后&#xff0c;會出現下面的界面 界面說明&#xff1a; Install CentOS 7 #安裝…

這份《.NET/C#面試手冊》超神啦!

這幾天給.neter們整理了一份《.NET/C#面試手冊》&#xff0c;目前大約4萬字左右&#xff0c;初衷也很簡單&#xff0c;就是希望在面試的時候能夠幫助到大家&#xff0c;減輕大家的負擔和節省時間。對于沒有跳槽打算的也可以復習一下相關知識點&#xff0c;就當是查缺補漏&#…

Dinic算法----最大流常用算法之一

——沒有什么是一個BFS或一個DFS解決不了的&#xff1b;如果有&#xff0c;那就兩個一起。 最大流的$EK$算法雖然簡單&#xff0c;但時間復雜度是$O(nm^2)$&#xff0c;在競賽中不太常用。 競賽中常用的$Dinic$算法和$SAP$&#xff0c;其實也不太難。 那么&#xff0c;$Dinic$算…

springcloud~Eureka實例搭建

服務端 build.gradle配置 dependencies {compile(org.springframework.cloud:spring-cloud-starter-netflix-eureka-server)testCompile(org.springframework.boot:spring-boot-starter-test) }dependencyManagement {imports {mavenBom "org.springframework.cloud:sprin…

php5.3教程,Php 5.3發布

PHP 5.3.4 特性&#xff1a; 增加對zip 流的統計支持 新增 follow_location (默認啟用)支持 增加一個 3rd parameter to get_html_translation_table Implemented FR #52348, added new constant ZEND_MULTIBYTE to detect zend multibyte at runtime. Multiple improvements t…

javascript學習筆記 null和undefined

null是javascript語言的關鍵字&#xff0c;它表示一個特殊值&#xff0c;常用來描述“空值”。對null執行typeof預算&#xff0c;結果返回字符串“object”&#xff0c;也就是說&#xff0c;可以將null認為是一個特殊的對象值&#xff0c;含義是“非對象”。但實際上&#xff0…

C# 為什么高手都是用IsNullOrWhiteSpace對字符串判空?

判斷字符串為空有好幾種方法&#xff1a;方法一&#xff1a; 代碼如下&#xff1a;static void Main(string[] args){string str "";if (str ""){Console.WriteLine("a is empty"); ;}Console.ReadKey();}運行結果&#xff1a;a is empty這樣…

使用bcftools提取指定樣本的vcf文件(extract specified samples in vcf format)

1、下載安裝bcftools。 2、準備樣本ID文件&#xff0c;這里命名為samplelistname.txt&#xff0c;一個樣本一行&#xff0c;如下所示&#xff1a; sample1 sample2 sample3 3、輸入命令&#xff1a; bcftools view -S samplelistname.txt /1000genomes/ALL.chr16.phase3_shapei…

iostat相關參數說明——await:平均每次設備I/O操作的等待時間 (毫秒),如果%util接近 100%,說明產生的I/O請求太多...

iostat是I/O statistics&#xff08;輸入/輸出統計&#xff09;的縮寫&#xff0c;iostat工具將對系統的磁盤操作活動進行監視。它的特點是匯報磁盤活動統計情況&#xff0c;同時也會匯報出 CPU使用情況。同vmstat一樣&#xff0c;iostat也有一個弱點&#xff0c;就是它不能對某…

php里面sql是什么意思,MySQL和SQL是什么?MySQL和SQL之間的區別有哪些

MySQL和SQL之間的區別有哪些&#xff1f;很多PHP的初學者&#xff0c;對MySQL&#xff0c;MyAdmin和SQL有什么區別并不是很清楚&#xff1f;下面 第一PHP社區 就帶領大家來學習一下MySQL和SQL之間的區別。【推薦閱讀&#xff1a;MySQL什么意思】一&#xff1a;什么是SQLSQL是一…

Blazor University (51)依賴注入 —— 擁有多個依賴項:錯誤的方式

原文鏈接&#xff1a;https://blazor-university.com/dependency-injection/component-scoped-dependencies/owning-multiple-dependencies-the-wrong-way/擁有多個依賴項&#xff1a;錯誤的方式OwningComponentBase[1] 類是一個合適的解決方案&#xff0c;當我們需要我們的組件…

Centos的yum源更換為國內的阿里云源

1、備份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2、下載新的CentOS-Base.repo 到/etc/yum.repos.d/ CentOS 5 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo 或者 curl -o /etc/yum.repo…