精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一個超經典WinForm,WPF卡死問題的終極反思

開發 前端
Harmony作為一款運行時C#方法修改器,借助它我完全可以將一些邏輯注入到 MarshalingControl..ctor 中,比如記錄下初始化該方法的 堆棧信息 ,是不是就可以輕松找到這個非主線程控件到底是誰?對不對,有了思路,我們在 nuget 上引用 Lib.Harmony ,上代碼說話。

一、背景

1. 講故事

寫這篇文章起源于訓練營里一位朋友最近在微信聊到他對這個問題使用了一種非常切實可行,簡單粗暴的方式,并且也成功解決了公司里幾個這樣的卡死dump,如今在公司已是靈魂級人物,讓我也嘗到了什么叫反哺!對,這個東西叫 Harmony, github網址:https://github.com/pardeike/Harmony,一個非常牛逼的C#程序函數修改器。

二:卡死問題的回顧

1. 故障成因

為了方便講述,先把 WinForm/WPF 程序故障的調用堆棧給大家呈現一下。

0:000:x86> !clrstack
OS Thread Id: 0x4eb688 (0)
Child SP       IP Call Site
002fed38 0000002b [HelperMethodFrame_1OBJ: 002fed38] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean)
002fee1c 5cddad21 System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean)
002fee34 5cddace8 System.Threading.WaitHandle.WaitOne(Int32, Boolean)
002fee48 538d876c System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)
002fee88 53c5214a System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
002fee8c 538dab4b [InlinedCallFrame: 002fee8c] 
002fef14 538dab4b System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
002fef48 53b03bc6 System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback, System.Object)
002fef60 5c774708 Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke(Boolean, System.Object[])
002fef94 5c6616ec Microsoft.Win32.SystemEvents.RaiseEvent(Boolean, System.Object, System.Object[])
002fefe8 5c660cd4 Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(Int32, IntPtr, IntPtr)
002ff008 5c882c98 Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, IntPtr)
...

這個程序之所以被卡死,底層原因到底大概是這樣的。

  • 程序在t1時間,有非主線程創建了控件。
  • 程序在t2時間,用戶主動或被動做了 遠程連接,Windows主題色刷新 等操作,這種系統級操作Windows需要同步刷新給所有UI控件。
  • 那些非主線程控件由于沒有 MessageLoop 機制,導致主線程給這些UI發消息時得不到響應,最終引發悲劇。

t2時間的卡死是由于t1時間的錯誤創建導致,要想在dump中反向追溯目前是無法做到的,所以要想找到禍根需要監控t1,即MarshalingControl到底是誰創建的,為此我也寫過兩篇文章來仔細分析此事。

  • (一個超經典 WinForm 卡死問題的再反思 )[https://www.cnblogs.com/huangxincheng/p/16868486.html]
  • (一個超經典 WinForm 卡死問題的最后一次反思)[https://www.cnblogs.com/huangxincheng/p/17654394.html]

第一種方式是啟動 windbg 對 System_Windows_Forms_ni System.Windows.Forms.Application+MarshalingControl..ctor 進行攔截,說實話這種方式很多程序員搞不定,原因在于windbg的使用門檻較高,現實中很多程序員連CURD都沒摸明白,所以可想而知了。。。

第二種方式是啟動 perfview 對 winform/wpf 程序進行監控,直到程序出現卡死停止收集。最后在錄播中尋找 MarshalingControl..ctor 的調用棧,這種方式也有不可行的時候,如果說卡死發生在程序啟動的10天后,那這個錄播文件將會超級超級大,或者有更極端的情況發生。

所以這兩種方案都有各自的優缺點,現實可行性雖然有,但不高。。。今天作為終結篇,必須把這個問題安排掉,繼續提供兩種切實可行的方案。

三:兩種修改方案

1. 使用 Harmony 注入

Harmony作為一款運行時C#方法修改器,借助它我完全可以將一些邏輯注入到 MarshalingControl..ctor 中,比如記錄下初始化該方法的 堆棧信息 ,是不是就可以輕松找到這個非主線程控件到底是誰?對不對,有了思路,我們在 nuget 上引用 Lib.Harmony ,上代碼說話。

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var harmony = new Harmony("一線碼農聊技術");

            Type applicationType = typeof(Application);
            Type marshalingControlType = applicationType.GetNestedType("MarshalingControl", BindingFlags.NonPublic);
            ConstructorInfo constructor = marshalingControlType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);

            var prefix = typeof(HookMarshalingControl).GetMethod("OnActionExecuting");

            harmony.Patch(constructor, new HarmonyMethod(prefix));
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            Button btn = new Button();
            var query = btn.Handle;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }

    /// <summary>
    /// Hook MarshalingControl 的描述類
    /// </summary>
    public class HookMarshalingControl
    {
        /// <summary>
        /// 原生方法之前執行的 action
        /// </summary>
        public static void OnActionExecuting()
        {
            Console.WriteLine("----------------------------");
            Console.WriteLine($"控件創建線程:{Thread.CurrentThread.ManagedThreadId}");
            Console.WriteLine(Environment.StackTrace);
            Console.WriteLine("----------------------------");
        }
    }

卦中的代碼邏輯我就不詳述了,核心就是將 OnActionExecuting 方法注入到 MarshalingControl..ctor 構造函數里,把程序運行起來后觀察 output 窗口,截圖如下:

圖片圖片

終于是一個臥槽,禍根居然是一個 tid=3 的線程初始化了 new Button() 控件。。。

2. 使用 DnSpy

Harmony 作為一款修改器,它對程序的侵入性是非常高的,目前還是有一些bug,比如對 .NET7 的支持還不是很好,但相對 perfview 和 windbg 的方式已經非常輕量級了,極大的降低了使用門檻。

問題來了,那有沒有一種對程序無侵入,可行性超高的方式呢?當然是有的,dnspy 此時可以閃亮登場,用過 dnspy 的朋友應該知道它是一款輕量級,免安裝綠色的調試器,當然除了調試器功能,它還是一款程序集修改器,可以實現 Harmony 的所有功能,在實踐中我們可以將 dnspy copy 到客戶機使用 啟動調試 或者 附加進程 的方式對程序進行干預。

如何使用 dnspy 對 MarshalingControl..ctor 進行干預呢?可以使用 斷點日志 的功能,日志信息如下:

控件創建線程:{Environment.CurrentManagedThreadId} \n $CALLSTACK

圖片圖片

有些人可能要問了 $CALLSTACK 是什么東西?很顯然是堆棧信息,除了這個關鍵詞還有很多,具體可以看后面的 問號面板。

圖片圖片

接下來把程序跑起來,觀察 output面板。

圖片圖片

從面板中可以清楚的看到,原來有個 tid=3 的線程創建了一個 Button 控件,這就是我們要找的禍根。

到這里,可能有些人要說,dnspy 啟動 exe 的方式因為各種原因在我們這邊行不通,有沒有其他的方式呢?當然是有的,我們還可以在程序啟動之后以 進程附加 的方式注入,同樣也是一種非常可行且低侵入的方式。

為了能夠更早的介入,可以在 Form1 初始化之前彈一個MessageBox,有更好的方式大家也可以說一下,感謝。參考代碼如下:

public partial class Form1 : Form
    {
        public Form1()
        {
            MessageBox.Show("開啟你的注入吧...");
            InitializeComponent();
        }
    }

彈框之后,使用 dnspy 的進程附加。

圖片圖片

附加好了之后關閉彈框讓程序繼續運行,點擊 buttton 按鈕,可以看到 output 上的輸出。

11:20:01.548 控件創建線程:<<<當線程位于不安全狀態時無法對表達式進行求值。按步調試或運行直到觸發斷點。>>>  
11:20:01.550    System.Windows.Forms.Application.MarshalingControl.MarshalingControl
11:20:01.551  System.Windows.Forms.Application.ThreadContext.MarshalingControl.get
11:20:01.552  System.Windows.Forms.WindowsFormsSynchronizationContext.WindowsFormsSynchronizationContext
11:20:01.553  System.Windows.Forms.WindowsFormsSynchronizationContext.InstallIfNeeded
11:20:01.553  System.Windows.Forms.Control.Control
11:20:01.554  System.Windows.Forms.ButtonBase.ButtonBase
11:20:01.554  System.Windows.Forms.Button.Button
11:20:01.554  WindowsFormsApp1.Form1.backgroundWorker1_DoWork
11:20:01.555  System.ComponentModel.BackgroundWorker.OnDoWork
11:20:01.555  System.ComponentModel.BackgroundWorker.WorkerThreadStart
11:20:01.556  System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage
11:20:01.556  System.Threading.ExecutionContext.RunInternal
11:20:01.557  System.Threading.ExecutionContext.Run
11:20:01.557  System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem
11:20:01.557  System.Threading.ThreadPoolWorkQueue.Dispatch
11:20:01.558  [本機到托管的轉換]
11:20:01.558

這里稍微提醒一下,tid 在這里沒有顯示出來,大家可以換成問號面板上的關鍵詞 $TID 即可,不過TID不是最重要的,最重要的是調用棧給弄出來了。

四、總結

作為一名專業的 .NET高級調試師,在這個經典卡死的問題溯源上一直沒有提供非常好的解決方案,還是有些內疚的,在我的高級調試之旅中還是會不間斷的收到類似dump,相信這篇文章之后,不再有人被它所困擾!

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2013-01-24 09:49:58

創業華為辭職

2013-09-25 10:28:42

諾基亞經典

2010-08-06 14:05:56

WPF

2023-03-01 10:19:23

2024-09-23 00:01:00

TailwindCSSSASS

2017-01-15 21:14:59

2011-04-14 15:55:35

WPF.NET

2025-11-18 09:30:57

2009-07-24 11:29:33

WinForm表單窗體

2022-05-12 09:17:06

SQLPython

2009-03-13 10:45:10

程序員技術人員

2014-04-16 11:39:52

2024-05-20 01:10:00

Promise變量

2009-12-28 10:40:13

WPF調用Winfor

2009-03-18 09:28:14

Linux操作系統技巧

2020-09-27 09:45:50

數字化轉型首席信息官IT領導者

2015-12-04 15:39:27

產品服務反思

2010-05-31 14:22:25

RFID安全

2024-02-28 08:12:25

SSE接口代理

2020-03-18 15:00:37

BasiliskFirefox瀏覽器
點贊
收藏

51CTO技術棧公眾號

亚洲欧美视频在线观看| 久久久亚洲一区| 精品国产伦一区二区三区免费| 美女扒开大腿让男人桶| 天堂资源中文在线| 美女国产一区二区三区| 欧美日韩高清在线观看| 成人h动漫精品一区| 成人影院在线免费观看| 亚洲一区二区三区国产| 日韩av高清在线播放| 精品人妻一区二区三区四区不卡 | 99久久精品免费看| 国产精品高潮呻吟久久av无限 | 欧美日韩精品二区| 一本久道久久综合| 亚洲欧美日韩免费| 国产一区二区福利视频| 国产成人精品日本亚洲专区61| 538任你躁在线精品视频网站| 自拍自偷一区二区三区| 日韩精品一区二区三区在线观看 | 九九热国产精品视频| 五月天亚洲色图| 欧美一区二区二区| 九九热免费精品视频| aa视频在线观看| 成人免费在线视频| 先锋影音亚洲资源| 三级视频在线| 国产.欧美.日韩| 国产一区视频在线播放| 99久热在线精品996热是什么| 欧美伊人久久| 北条麻妃99精品青青久久| 国产美女精品久久| 欧美福利在线播放网址导航| 日韩一区二区高清| 中文字幕66页| 桃花岛tv亚洲品质| 欧美性生交xxxxxdddd| 欧美精品久久久久久久久久久| 免费在线观看黄| 欧美激情中文字幕一区二区| 欧美高清性xxxxhd| 无码精品人妻一区二区| 丁香桃色午夜亚洲一区二区三区| 亚洲va欧美va国产综合剧情 | 秋霞电影网一区二区| 国产69久久精品成人| 国产精品美女毛片真酒店| 欧美人成在线| 欧美成人精品不卡视频在线观看| 国产美女福利视频| 亚洲精品在线观看91| 日韩一区二区欧美| 欧美一级特黄高清视频| 国产又粗又硬视频| 亚洲高清影院| 欧美日本在线看| 亚欧激情乱码久久久久久久久| 免费观看成人性生生活片| 欧美天堂在线观看| 国产偷人视频免费| 台湾成人免费视频| 欧美三级电影在线看| 污污网站免费看| 欧美黄页免费| 日韩一级免费观看| aaa黄色大片| 日韩一级电影| 伊人av综合网| 四虎精品免费视频| 极品日韩av| 91av在线免费观看视频| 波多野结衣啪啪| 美女性感视频久久| 91精品中文在线| 欧美一区二不卡视频| 久久人人97超碰com| 深夜福利成人| 久久黄色美女电影| 午夜av一区二区三区| 黄色a级片免费| 国产国产一区| 欧美va亚洲va| 黄色aaa视频| 天天做天天爱综合| 久久频这里精品99香蕉| 国产91精品看黄网站在线观看| 美女在线一区二区| yellow视频在线观看一区二区| 天天综合天天综合| 国产精品欧美经典| 97中文字幕在线| 成人香蕉视频| 91麻豆精品国产91久久久更新时间 | 黄色一区二区在线| 中文字幕一区二区三区乱码| av电影免费在线观看| 午夜电影久久久| 欧美日韩一区二区三区69堂| 天堂久久av| 亚洲视频在线免费观看| 欧美日韩在线视频免费播放| 亚洲综合精品四区| 亚洲一区二区三区久久| 性xxxxbbbb| 亚洲色图在线看| 国产亚洲天堂网| 麻豆精品久久| 亚洲天堂av在线免费观看| 久久精品视频免费在线观看| 日韩精品一二三| 国产乱子伦精品| 午夜小视频在线| 精品人伦一区二区三区蜜桃免费 | 日本妇女毛茸茸| 久久精品男女| 福利视频一区二区三区| 啊v视频在线| 天天亚洲美女在线视频| 人妻换人妻仑乱| blacked蜜桃精品一区| 91国产中文字幕| www.桃色av嫩草.com| 中文乱码免费一区二区| 黄色片视频在线播放| 国产主播性色av福利精品一区| 中文字幕一精品亚洲无线一区 | 国产18无套直看片| 午夜在线精品偷拍| 好吊妞www.84com只有这里才有精品 | 丁香六月综合激情| 精品在线一区| av电影在线地址| 日韩免费高清视频| av激情在线观看| 激情综合色播激情啊| 性欧美精品一区二区三区在线播放 | 亚洲综合婷婷久久| 成人精品亚洲| 国产精品久久久久不卡| 国产在线观看免费| 一本大道av伊人久久综合| 99久久国产精| 国产日韩欧美三区| 免费国产一区二区| xx欧美视频| 亚洲美女喷白浆| 成年人av网站| 国产欧美一区二区三区鸳鸯浴 | 国产成人av电影在线观看| 99热一区二区三区| 日本成人手机在线| 欧美疯狂性受xxxxx另类| 亚洲国产www| 一区二区三区四区精品在线视频 | 亚洲一区二区视频在线播放| 国产精品妹子av| 成 人 黄 色 小说网站 s色| 国产精品国产三级国产在线观看| 91色在线视频| 日韩免费影院| 亚洲国产精品推荐| 亚洲午夜18毛片在线看| 国产婷婷色一区二区三区在线| 欧美日韩怡红院| 久久精品国产99久久| 成人xxxxx| 丝袜美腿av在线| 亚洲国产私拍精品国模在线观看| 中文字幕第38页| 婷婷在线免费视频| 亚洲免费三区一区二区| av电影中文字幕| a91a精品视频在线观看| 日本一区二区三不卡| 亚洲美女色播| 国内精品久久久久影院 日本资源 国内精品久久久久伊人av | 欧美a在线播放| 国产精品一区二区三区乱码| 人妻av无码专区| 色婷婷综合久久久久久| 国产精品入口日韩视频大尺度| 成人免费高清| 亚洲精品久久久久| 在线观看亚洲一区二区| 一区二区在线观看视频在线观看| av无码一区二区三区| 青青青伊人色综合久久| 国产一二三区在线播放| 亚洲婷婷影院| 91亚洲一区精品| 中文字幕21页在线看| 久久久精品在线| 亚洲色图欧美视频| 7777精品伊人久久久大香线蕉的 | 色综合亚洲图丝熟| 日韩在线观看高清| 午夜成人鲁丝片午夜精品| 欧美日韩国产影片| 天天综合网入口| 亚洲免费成人av| 99久久久无码国产精品性| 国产伦精品一区二区三区免费| wwwxxx黄色片| 亚洲午夜一级| 中国成人亚色综合网站| 女人av一区| 国产精品区二区三区日本| 日韩在线激情| 日韩av电影在线播放| 日韩欧美一起| 久久精品欧美视频| 十八禁视频网站在线观看| 人成在线免费网站| 欧美老女人在线视频| yjizz视频网站在线播放| 亚洲精品国产免费| 国产 欧美 自拍| 91麻豆精品国产91久久久久久久久| 五月婷婷激情视频| 亚洲福利视频一区二区| 91高清免费观看| 日本一区二区综合亚洲| 中文字幕在线播放视频| 国产成人免费在线观看不卡| 日本国产一级片| 丝袜诱惑制服诱惑色一区在线观看 | 欧美日韩国产精品成人| 天堂网视频在线| 精品国产乱码久久久久酒店 | 熟女俱乐部一区二区| jlzzjlzz国产精品久久| 国产日韩视频一区| 国产成人av福利| 国产又粗又猛又爽又黄| 国产精品一区二区三区网站| 欧美视频亚洲图片| 狠狠色狠狠色综合系列| 欧美伦理片在线观看| 日韩电影在线观看电影| 黄色一级二级三级| 日韩精品国产欧美| 国产天堂在线播放| 久久这里只有| 污污视频网站免费观看| 日韩电影免费在线看| 天天天干夜夜夜操| 日韩影院在线观看| 亚洲涩涩在线观看| 韩国女主播成人在线| 日韩av加勒比| 国产成人午夜99999| 在线播放第一页| 99在线精品一区二区三区| 99久久人妻精品免费二区| 91一区二区在线| 久久久亚洲av波多野结衣| 久久网这里都是精品| 久久偷看各类女兵18女厕嘘嘘| 高潮毛片又色又爽免费| 欧美在线影院一区二区| 国产又粗又猛又爽又黄的| 日韩欧美视频一区| 色欲av伊人久久大香线蕉影院| 精品视频偷偷看在线观看| 国产免费av高清在线| 最新国产精品亚洲| 日本无删减在线| 欧美一区二区色| 精品久久在线| av激情久久| 亚洲第一论坛sis| 亚洲.欧美.日本.国产综合在线| 久久中文字幕二区| 黄色激情在线视频| 日韩福利视频网| 在线观看视频你懂得| 91丨porny丨蝌蚪视频| 91视频免费看片| 亚洲一区日韩精品中文字幕| 国产精品自拍99| 欧美日韩三级在线| 老司机午夜福利视频| 一区二区三区视频免费| 色屁屁www国产馆在线观看| 欧美一区在线直播| 国产精品18| 九色91国产| 中文字幕免费一区二区三区| 青青青免费在线| 老司机精品视频在线| 亚洲综合自拍网| 综合电影一区二区三区| 免费在线不卡视频| 日韩视频国产视频| 国产69精品久久app免费版| 久久99久久亚洲国产| 成人黄色视屏网站| 国产无套精品一区二区| 91麻豆精品国产91久久久平台| 国产二区视频在线| 久久99九九99精品| 丝袜美腿中文字幕| 亚洲尤物视频在线| 伊人网综合在线| 亚洲国产精品人久久电影| 成人免费看片| 国产精品爽黄69天堂a| 秋霞蜜臀av久久电影网免费| 这里只有精品66| 日韩国产精品久久| 亚洲熟女乱综合一区二区三区| 亚洲乱码中文字幕| 最近中文字幕免费观看| 国产精品美女久久久久久2018 | 国产精品久久观看| 欧美色图另类小说| 国产suv一区二区三区88区| 特级西西人体高清大胆| 欧美日韩亚洲视频一区| 亚洲美女综合网| 美女少妇精品视频| 日韩成人一区| 性欧美.com| 在线播放中文字幕一区| 高清毛片aaaaaaaaa片| 日韩视频在线免费| 欧美极品免费| 欧美日韩国产高清视频| 亚洲最黄网站| 岛国精品一区二区三区| 一区二区国产视频| 精品人妻午夜一区二区三区四区| 精品国产拍在线观看| 欧美大片网站| 一区二区av| 麻豆成人在线观看| 日本爱爱爱视频| 欧美性感一类影片在线播放| 你懂的在线观看| 国产成人黄色av| 精品国产乱码久久久久久蜜坠欲下 | 一区二区免费在线观看视频| 亚洲一区二区三区四区中文字幕| 国产高清免费在线观看| 九九热视频这里只有精品| 欧美成人一级| 欧美一级爱爱视频| 处破女av一区二区| 日韩精品一区二区在线播放 | 免费不卡视频| 91精品久久久久久综合乱菊| 999久久久国产精品| 日本网站在线看| 亚洲综合免费观看高清在线观看| www三级免费| 午夜精品蜜臀一区二区三区免费| 清纯唯美亚洲经典中文字幕| www.国产区| 中文字幕一区二区三区在线不卡 | 91国产丝袜播放在线| 日韩av中文字幕在线播放| 日本电影欧美片| 一区二区在线观看网站| 国产成人精品免费看| 亚洲伊人成人网| 一本一本久久a久久精品综合小说 一本一本久久a久久精品牛牛影视 | 欧美在线|欧美| 在线观看免费版| 亚洲专区在线视频| 亚洲国产精品第一区二区三区| 中文字幕在线免费看线人| 在线观看日韩高清av| 麻豆影院在线| 国产一区二区视频在线免费观看| 久久精品官网| 人妻久久一区二区| 日韩电影中文字幕在线| 成人在线免费电影网站| 97在线免费视频观看| 久久蜜桃av一区二区天堂| 亚洲性生活大片| 午夜免费日韩视频| 欧洲毛片在线视频免费观看| 国产精品日日摸夜夜爽| 在线视频一区二区三| 日本孕妇大胆孕交无码| 欧美亚洲免费高清在线观看| 国产精品综合久久| 日本三级小视频| 美女撒尿一区二区三区| 国产麻豆精品久久| 欧美一级片在线免费观看| 欧洲在线/亚洲| av影院在线| 在线观看日韩羞羞视频| 久久综合色之久久综合|