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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...