【疑難系列】 是程式卡住了還是怎麼了?

小彬發表於2019-06-16

起因

客戶說:“今天的預報又沒有發出去,幫忙看下怎麼回事?”

“...”

經過

登陸伺服器,發現程式一直在列印

running
running
running
...

這是程式碼中寫的

        public static void Main(string[] args)
        {
            Console.Title = string.Format("Grib2壓碼程式 請勿關閉");
            ActiveMq();
            while (hasMessage)
            {
                Console.WriteLine("running");
                Thread.Sleep(1000);
            }
        }

程式通過啟動ActiveMQ,然後判斷是否仍有訊息在處理,如果在處理就Sleep當前執行緒,等待處理完畢

當接收到訊息時的處理主邏輯:


        public static void OnMessage(IMessage message)
        {
            var msg = message as ITextMessage;
            if(msg != null)
            {
               
                hasMessage = true;
                String date = msg.Text;
                Compress(date);
                mq.send(date);
                hasMessage = false;
            }
        }

那麼問題應該是Compress或者 mq.send 一直在處理,卡住了??

因為是.net程式,所以不能用jstack來分析執行緒了

通過windows自帶的工作管理員,把程式dump出來

如何dump

然後使用windbg分析一下執行緒,直接通過檔案, "open dump file",開啟匯出的dmp檔案。

dump檔案結果

windbg第一次使用,不是很懂得使用,但是注意到右下角threads的執行緒資訊,發現只有一個主執行緒在執行!!

也就是說:我們的監聽執行緒退出了!!!

那麼,什麼情況下會退出呢?

一般是執行緒執行過程中丟擲異常沒有處理

檢查原始碼,發現程式沒有對出現異常做任何處理

所以,修改方案如下:

        public static void OnMessage(IMessage message)
        {
            var msg = message as ITextMessage;
            if(msg != null)
            {
               
                hasMessage = true;
                String date = msg.Text;
                if(Compress(date, 3))
                {
                    mq.send(date);
                }
                else
                {
                    mq.fail(date);
                }
                hasMessage = false;
            }
        }

        public static bool Compress(string date, int retry)
        {
            if (retry == 0)
            {
                return false;
            }
            try
            {
                Compress(date);
                return true;
            }
            catch (Exception ex)
            {
                Log.writeException(ex);
                return Compress(date, retry - 1);
            }
        }

將監聽訊息部分的程式碼進行修改,增加重試,並進行try catch異常處理,出現異常時,在檔案中記錄日誌

當然mq.send 也有可能出現異常,將send方法也進行try catch異常處理

替換程式,上線執行(這種問題看能否重現了,重現了就可以在error.log中找到了)

總結分析

windbg第一應用,表示很多資訊都看不懂

主執行緒中需要考慮子執行緒的異常,有些執行緒,你以為在執行,實際上它退出了

其它

面試的時候,面試官問我

“你遇到過最難解決的問題,你是怎麼解決的?”

“我特麼都是問題解決了就忘記了,所以沒啥印象”

不過,我是在心裡說的

所以,對於別人問我的問題,我決定記錄下來,免得將來忘記了

相關文章