博客 / 詳情

返回

dotnet未捕獲異常導致系統崩潰問題

一般情況下我們業務代碼不需要自己捕獲異常,因為目前我們常用框架都會自行處理異常,但是有些情況下需要自己處理異常,否則未處理的異常拋出會導致程序崩潰退出。

1.全局異常捕獲

// 1. AppDomain 未處理異常
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
    var exception = e.ExceptionObject as Exception;
    LogException(exception, "UnhandledException");
    
    if (e.IsTerminating)
    {
        // 進程即將終止
        EmergencyShutdown();
    }
};

// 2. Task 未觀察異常 (.NET 4.0+)
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
    LogException(e.Exception, "UnobservedTaskException");
    e.SetObserved(); // 防止進程崩潰
};

// 3. Windows Forms
if (Application.MessageLoop)
{
    Application.ThreadException += (sender, e) =>
    {
        LogException(e.ception, "ThreadException");
    };
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
}

// 4. WPF
Dispatcher.CurrentDispatcher.UnhandledException += (sender, e) =>
{
    LogException(e.Exception, "DispatcherUnhandledException");
    e.Handled = true; // 阻止進程崩潰
};

// 5. ASP.NET Core
// 在 Program.cs 中使用 UseExceptionHandler 中間件

2.Timer異常 和 異步void方法異常

定時器的事件方法中的代碼拋出來的異常,無法被全局異常捕獲,同樣異步void方法異常也是的,需要自行捕獲異常。

public class SafeTimer
{
    private readonly Timer _timer;
    
    public SafeTimer()
    {
        _timer = new Timer(OnTimerCallback);
    }
    
    private void OnTimerCallback(object state)
    {
        try
        {
            // 業務邏輯
        }
        catch (Exception ex)
        {
            // 記錄日誌,通知主線程
            LogException(ex);
        }
    }
}

3.StackOverflowException和OutOfMemoryException

這兩個異常業務無法捕獲的,因為它們發生時,程序以及沒有辦法在執行如何代碼了,只能靠上個文章中説的崩潰自動收集dump,然後去分析dump找出問題。
還有其他比如調用c代碼等不安全代碼,大部分時候也時無法捕獲,如果它們引起異常也很難捕獲。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.