dotnet 調試應用啟動閃退的方法

来源:https://www.cnblogs.com/lindexi/archive/2022/06/20/16394515.html
-Advertisement-
Play Games

在我國自動化控制領域應用較廣泛的工業自動化組態軟體有Wonderware公司InTouch、西門子公司Wincc、GE公司iFix。國內也有一些傳統組態軟體廠商,使用的功能和形式基本上十分類似,受當時開發環境和組態軟體框架的限制,也很難做較大的改變。 ...


應用程式如果啟動即閃退,那大部分時候日誌模塊還沒初始化完成,很難通過應用自身的啟動流程瞭解到應用啟動失敗的原因。本文來告訴幾個不同的方法用來調查應用啟動失敗的原因

應用啟動失敗的原因可能有很多,例如系統環境問題,例如寫個點逗比代碼,例如調用某個帶毒的庫。如果應用啟動失敗,可以在開發環境上復現,那無疑是十分好的事情,因為咱可以使用開發環境強大的 VisualStudio 調試工具進行調試

使用 VisualStudio 調試應用啟動失敗

在有符號的配合下,使用 VisualStudio 定位應用軟體啟動失敗在大多數時候都是比較輕鬆的。當然,沒有符號的話,也沒多少問題,至少可以快速定位到是哪個模塊

使用 VisualStudio 定位應用軟體啟動失敗的方法是讓 VisualStudio 啟動應用且進入調試模式。做法就是隨便找一個 dotnet 6 的項目,當然,如果是所要調試的應用的對應版本的代碼的項目那是最好的。點擊設置調試屬性,設置應用作為啟動路徑

在 VisualStudio 2022 下,打開設置調試屬性的界面可以是在項目上進行右擊,然後點擊屬性,找到調試頁面,點擊打開調試啟動配置文件即可看到,如下圖

接著點擊創建新配置文件,選擇可執行文件

接下來選擇需要調試啟動失敗的應用的路徑

為了同時捕獲一些本機異常,還請勾選“啟用本機代碼調試”也就是混合調試模式。本機異常包括 Window Runtime 拋出的異常,基礎的 Win32 調用包含的非返回值的錯誤的異常,以及外部 C++ 等庫的異常等

為了提升調試的成功率,還請在 VisualStudio 設置裡面,將所有的異常都打開進行捕獲,同時關閉僅我的代碼調試。打開所有異常捕獲的方法是在 調試->視窗->異常設置 裡面進行配置。簡單來說就是將能打鉤的全部打上,當然,你要是熟悉的話,那就少打鉤一些咯,反正多打鉤也沒啥問題

關閉僅我的代碼可以讓你調試到一些被優化的代碼。在咱 dotnet 的程式集裡面,對 Debug 下和 Release 下最大的不同在於勾選了優化代碼。如果勾選了僅我的代碼調試,那將只調試 Debug 生成的程式集,而預設忽略對 Release 的程式集的記錄。在大部分的調試下,這個模式都可以減少發佈的程式集的干擾,可以更加方便調試業務代碼。但是當前是在調試啟動失敗,啟動失敗可能是庫的鍋,需要調試發佈的程式集,推薦關閉僅我的代碼調試。關閉的方法是在 VisualStudio 的 工具-> 選項 -> 調試 裡面,去掉 啟用“僅我的代碼” 的選項

完成配置之後,在 VisualStudio 裡面,選擇剛纔創建的新配置作為啟動項進行啟動

推薦是第一次調試可以快速過,看看是不是有異常觸發,逐步去掉那些不影響啟動異常的干擾,嘗試找到導致啟動失敗的異常,即可進行快速定位

而啟動失敗還有一個隱藏的原因是寫了逗比代碼,自己退出的。那就需要自己進行調試,找到是哪個模塊退出了應用,可以在第一次調試的時候,通過輸出視窗找到應用的退出碼是多少,輔助定位邏輯。如果退出碼是一個零,那找找是不是存在 Environment.Exit(0); 類似的代碼,可以全局進行字元串查找對應的代碼。或者是 Main 函數執行完成,例如在 WPF 裡面調用了 Application.Current.Shutdown 進行退出

在開發環境上遇到應用啟動失敗,大部分時候都可以在 VisualStudio 的幫助下快速定位到為什麼啟動失敗

但是如果應用只是在用戶的設備上才失敗,那就沒那麼好玩了,接下來將告訴大家如何調試用戶端的應用啟動失敗

使用 dnSpy 調試應用啟動失敗

在用戶的設備上,如果應用啟動失敗了,如果此時應用自己的日誌模塊還沒初始化完成,那也不用慌,系統的事件查看器可能可以幫忙到你。打開系統的事件查看器,裡面也許記錄了一些應用啟動失敗的原因,例如是系統環境問題,比如是系統缺少了某個庫,或者是驅動問題。我之前很經常遇到的就是 WPF 應用啟動失敗是由顯卡驅動導致的,不過顯卡驅動問題基本上用不到多少的調試,稍微看一下就能看到了,系統的各個部分都會很奇怪

如何打開系統的事件查看器?在 Win10 下,右擊開始菜單按鈕,點擊事件查看器即可打開。打開之後,大部分時候都可以先去看 Windows 日誌裡面的應用程式的日誌,裡面也許有記錄應用的啟動失敗原因

但是有時候事件查看器記錄的也很迷,如下麵例子的啟動失敗的記錄

系統記錄了兩條相關的錯誤日誌,一條是 .NET Runtime 錯誤日誌,如下內容

Application: KajijuniLiguqujokemka.exe
CoreCLR Version: 6.0.522.21309
.NET Version: 6.0.5
Description: The process was terminated due to an internal error in the .NET Runtime at IP 00007FF9DAEBDA03 (00007FF9DACF0000) with exit code c0000005.

另一條是 Application Error 日誌,內容如下

錯誤應用程式名稱: KajijuniLiguqujokemka.exe,版本: 1.0.0.0,時間戳: 0x62571213
錯誤模塊名稱: coreclr.dll,版本: 6.0.522.21309,時間戳: 0x625708f4
異常代碼: 0xc0000005
錯誤偏移量: 0x00000000001cda03
錯誤進程 ID: 0x3814
錯誤應用程式啟動時間: 0x01d882fdfe019fc7
錯誤應用程式路徑: C:\lindexi\Code\lindexi\BeyajaydahifallChecheecaifelwarlerenel\KajijuniLiguqujokemka\bin\Debug\net6.0-windows\KajijuniLiguqujokemka.exe
錯誤模塊路徑: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.5\coreclr.dll
報告 ID: 45232171-a61e-46fa-b80b-248ad12f5fef
錯誤程式包全名: 
錯誤程式包相對應用程式 ID: 

這兩條日誌沒有能給咱很好的一個調試思路,只能說明應用確實掛了而已。不能說明是應用自己寫了逗比代碼,也不能證明是系統環境問題,也不能證明是調用庫的問題。想要瞭解為什麼,只能繼續往下進行調試

通過 dnSpy 神器可以輔助在用戶端進行調試。根本原因在於 VisualStudio 太龐大了,在用戶端安裝不太現實。但 dnSpy 是非常輕巧的,可以免安裝使用。相當於在用戶端跑一個輕巧的 VisualStudio 調試工具

支持 dotnet 6 版本的 dnSpy 下載地址請看 支持 dotnet 6 的 dnSpy 神器版本

調試的思路和上文的使用 VisuslStudio 調試的差不多,有稍微一點不同的是,需要先將要調試的 Exe 拖入到 dnSpy 中,然後點擊此 Exe 進行調試。同樣需要勾選異常等

使用 dnSpy 調試還有一個好處是,可以無須任何符號即可進行調試,十分方便

使用 ProcDump 進行 DUMP 分析

但是如果應用的啟動失敗不是每次都復現的,是概率復現的,那就不好玩了。以上兩個方法都是需要進行調試啟動的,而大家都知道,調試模式下和非調試模式下是有差別的,例如多線程執行的差別。如果剛好啟動是因為線程安全導致的問題,那麼調試下也許是復現不到的。對於不是每次都失敗的應用啟動,進行調試是非常想砸鍵盤的,有時候調試的好好的,應用就啟動成功了。有時候覺得沒問題,按下繼續,應用就啟動失敗了

或者是在用戶端,用戶有情緒了,不適合進行慢慢的調試。此時可以用到 ProcDump 工具輔助,在應用啟動時候的時候,將失敗時做一個 DUMP 文件,然後咱就可以將這個 DUMP 傳回開發的設備上慢慢進行分析

這個 ProcDump 是微軟極品工具箱的一個很有名的工具

官方下載地址: https://docs.microsoft.com/zh-cn/sysinternals/downloads/procdump

根據官方文檔可以瞭解到使用方法是在命令行使用如下參數,即可做到在應用因為異常掛掉自動捕獲 DUMP 文件

procdump.exe -e -t -w -ma <進程名>

參數的含義如下

  • -e : 當進程遇到未經處理的異常時寫入轉儲
  • -t : 進程終止時寫入轉儲。如果應用啟動失敗是自己逗比或者某個庫逗比調用了退出進程的方法,那也可以使用捕獲到
  • -w : 等待指定的進程啟動。大部分時候都是先運行 ProcDump 工具,然後再啟動應用,這樣 ProcDump 相當於監控應用啟動失敗或退出。如此即可採用 ProcDump 啟動進程調試應用啟動閃退
  • -ma : 獲取的是 Full Dump 文件,也就是包含所有內容的 DUMP 文件,雖然這個 DUMP 比較大,但是調試會根據方便。如果傳輸過程比較難,而且開發者也熟悉調試 DUMP 可以換用 -mm 命名寫入小型 DUMP 文件

假定需要調試的啟動失敗的應用是 KajijuniLiguqujokemka.exe 應用,那麼執行的命令如下

procdump.exe -e -t -w -ma KajijuniLiguqujokemka

如此即可在應用啟動閃退自動創建 DUMP 文件。創建好的 DUMP 文件可以採用 7z 工具壓縮一下再傳回開發機器,使用 7z 可以極大壓縮 DUMP 文件,因為 DUMP 文件裡面很多數據都是全 0 的

拿到 DUMP 文件之後,就需要開啟 DUMP 調試了。最簡單的 DUMP 調試是打開 VisualStudio 將 DUMP 文件拖進入,然後如開始的步驟先配置一下,然後點擊使用混合進行調試即可

核心是看調用堆棧,和局部變數視窗,找到是哪個模塊拋出異常或者退出。如果 VisualStudio 無法幫到你,那就只能換成 WinDbg 啦,不過這又是另外一個故事了

大家可以嘗試使用我放在 github 的代碼進行測試

更多請看 dotnet 代碼調試方法

博客園博客只做備份,博客發佈就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

知識共用許可協議
本作品採用知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我[聯繫](mailto:[email protected])。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Hi,我是Mic 一個工作了4年的粉絲,在面試的時候遇到一個這樣的問題。 “介紹一下Spring IOC的工作流程” 他說回答得不是很好,希望我能幫他梳理一下。 關於這個問題,我們來看看普通人和高手的回答。 普通人: 嗯。。。。。。。。 高手: 好的,這個問題我會從幾個方面來回答。 IOC是什麼 B ...
  • 前言 大家好,歡迎來到 Crossin的編程教室 ! 今天給大家分享的這個案例是用 Python+OpenCV 實現了自動掃雷,並突破了人類的世界記錄。(當然 這不算哈) 咱們廢話不多說,先看成果~ 中級 - 0.74秒 3BV/S=60.81 相信許多人很早就知道有掃雷這麼一款經典的游(顯卡測試) ...
  • 此問題是無法做到100%場景一致性的,只能做到基本一致或者最終一致性。 推薦使用的方案 延時雙刪 原理:先進行緩存清除,再執行update,最後(延遲N秒)再執行緩存清除。(延遲N秒)的時間要大於一次寫操作的時間。 一般執行流程: 服務節點刪除 redis 主庫數據。 服務節點修改 mysql 主庫 ...
  • 大佬的理解->Java多線程(一)多線程基礎 大佬的理解->Java多線程(二)常用的實現多線程的兩種方式 1、繼承Thread類 ​ 繼承Thread必須重寫run方法,(具體業務執行方法,需要執行的業務方法,定義在此方法中),註意此方法是線程啟動後線程自動調用的; 案例 public class ...
  • 前言 還有多少人不會python的控制結構,在評論區告訴我,讓我一個個點名提問。今天,就教會你python的控制結構… 分行與縮進 分行 •一條語句占用一行 •過長的語句可以占用多行,使用\或()控制換行 •[]、{}、()可以直接跨越多行,在列表、字典、元組中需要換行的時候也可以不用添加續行符 a ...
  • 3 Skywalking源碼導入 接上文,已經學習了Skywalking的應用,接下來我們將剖析Skywalking源碼,深度學習Skywalking Agent。 3.1 源碼環境搭建 當前最新版本是8.3.0,我們首先找到8.3.0的版本,然後下載並導入到IDEA,下載地址 https://gi ...
  • 《乘風破浪的姐姐3》王心凌一騎絕塵,破收視率,多年後再次全網爆火,某音截止現在差不多3500W粉絲,五月份熱門女星排名,弔打其它所有人,不愧是我女神! 但是這個熱度,感覺她的歌曲和MV,已經離收費越來越近了,於是我連夜用Python把所有MV 和歌曲離線,今天先給大家分享MV的方法。 女神鎮樓! 話 ...
  • 序列號 序列號是序列化和反序列化的唯一標識,是一個長整型數值; 如果類中不自己定義序列號,系統會自動生成一個序列號; 當一方實體類發生改變,而調用方的序列號是不會跟著改變的,不知道對象已修改,會導致兩邊序列號不一致,反序列化失敗; 所以要求必須手動生成一個序列號; 手動生成序列號後,可以解決目標類發 ...
一周排行
    -Advertisement-
    Play Games
  • public static void GetRegistData() { string name = "huishuangzhu"; //搜索到註冊表根目錄 RegistryKey hkml = Registry.ClassesRoot; //搜索到註冊表根目錄下的XXX文件夾。 RegistryK ...
  • 用acme.sh自動部署功能變數名稱證書 安裝ACME 目前使用量最大的免費SSL證書就是Let’s Encrypt,自2018-03開始,Let’s Encrypt官方發佈上線了免費的SSL泛功能變數名稱證書,目前通過DNS方式獲取比較快,國內可以通過鵝雲的DNSPod功能變數名稱API或者貓雲功能變數名稱API自動簽發Let’ ...
  • 經常看到有群友調侃“為什麼搞Java的總在學習JVM調優?那是因為Java爛!我們.NET就不需要搞這些!”真的是這樣嗎?今天我就用一個案例來分析一下。 昨天,一位學生問了我一個問題:他建了一個預設的ASP.NET Core Web API的項目,也就是那個WeatherForecast的預設項目模 ...
  • 1、環境搭建 1.1 依賴 <!-- nacos註冊中心 註解 @EnableDiscoveryClient --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba- ...
  • ULID:Universally Unique Lexicographically Sortable Identifier(通用唯一詞典分類標識符) UUID:Universally Unique Identifier(通用唯一標識符) 為什麼不選擇UUID UUID 目前有 5 個版本: 版本1: ...
  • 虛基類/抽象類 抽象類:有純虛函數的類 虛繼承 通過修飾繼承方式, 如代碼2是虛繼承,被虛繼承的類稱為虛基類 虛繼承派生類的記憶體佈局方式 先是vbptr => 派生類的數據 =>基類的數據 , 對比代碼1和代碼2,發現原本基類數據在前面,派生類數據在後面,但是在虛繼承的時候 基類數據方式放到了後面, ...
  • 下麵給出 Kafka 一些重要概念,讓大家對 Kafka 有個整體的認識和感知,後面還會詳細的解析每一個概念的作用以及更深入的原理 • Producer:消息生產者,向 Kafka Broker 發消息的客戶端。 • Consumer:消息消費者,從 Kafka Broker 取消息的客戶端。 • ...
  • 前面介紹了對稱加密演算法,本文將介紹密碼學中另一類重要應用:消息摘要(Digest),什麼是消息摘要?簡單的定義是:對一份數據,進行一個單向的Hash函數,生成一個固定長度的Hash值,這個值就是這份數據的摘要,也稱為指紋。 ...
  • 弟弟最近要考試,臨時抱佛腳在網上找了一堆學習資料複習,這不剛就來找我了,說PDF上有水印,影響閱讀效果,到時候考不好就怪資料不行,氣的我差點當場想把他揍一頓! 算了,弟弟長大了,看在打不過他的份上,就不打他了~ 稍加思索,我想起了Python不是可以去水印?說搞就搞! 去除水印原理 去除方法: 用 ...
  • 作者:陳昌浩 1 導讀 if…else…在代碼中經常使用,聽說可以通過Java 8的Function介面來消滅if…else…!Function介面是什麼?如果通過Function介面介面消滅if…else…呢?讓我們一起來探索一下吧。 2 Function介面 Function介面就是一個有且僅有 ...