CLR如何捕獲並處理異常

對於任何一個.NET應用程序中的類,其所包含的方法都有一個異常處理表,如果此方法中沒有try...catch...finally語句,則異常處理表爲空。(即此方法生成的IL指令中不包括任何的異常處理子句)

根據之前的學習我們知道,當應用程序擁有多層嵌套的異常捕獲結構時,如果最底層發生了異常,CLR將優先在引發異常的那一層去搜索catch語句塊,看看有沒有“兼容”此類型異常的處理代碼,如果沒有,跳到上一層去查找,如果上一層還沒有,繼續搜索上一層的上一層,直到應用程序的最頂層。

這就是CLR處理嵌套異常捕獲結構應用程序的第一輪遍歷——查找合適的異常處理程序。

如果在某一層中找到了異常處理代碼,CLR並不會馬上執行,而是回到事故現場,進行第二輪遍歷,執行所有中間層的finally語句塊,然後執行找到的異常處理代碼,最後再從本層開始一直遍歷到最頂層,執行所有的finally語句塊。

這就是.NET應用程序異常處理策略的兩輪遍歷。

示例代碼如下:

class ExceptionA : Exception
{
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            throw new ExceptionA();
        }
        catch (FormatException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch (NullReferenceException ex)
        {
            Console.WriteLine(ex.Message);
        }
        catch (ExceptionA ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}

生成的IL指令代碼如下:

當.NET應用程序運行時,如果某個方法引發了一個異常,CLR首先會將相應的異常對象推入計算堆棧,然後掃描此方法的所包含的異常處理表查找處理程序,其處理過程大致如下:

CLR獲取引發異常的IL指令地址,然後從上到下的掃描異常處理表,取出每個catch子句中.try關鍵字後面跟着的用於定位“塊”的起始和結束地址,判斷一下引發異常的IL地址是否落入此地址範圍內,如果是,取出catch關鍵字後面跟着的異常類型,對比一下是否與拋出的異常對象類型一致(或兼容)如果滿足,CLR取出handler後面的兩個IL地址,“準備”執行這兩個地址指定範圍內的IL指令(其實就是對應的catch語句塊的異常處理代碼)。

如果本方法的異常處理表中未找到合適的catch子句,CLR會依據引發異常的線程所關聯的方法調用堆棧,查找此方法的調用者所包含的異常處理表。

此過程將一直進行下去,直到找了一個可以處理異常的處理程序爲止。

假設CLR在整個方法調用堆棧的某一個方法中找到了可處理異常的catch語句,它就做好了執行此語句定義的異常處理代碼的準備。

掃描並查找相匹配的catch子句過程是CLR異常處理流程的第一輪。

當找到了合適的異常處理代碼後,CLR再回到原地,再次掃描引發異常方法的異常處理表,這次CLR關注的不再是catch子句,而是finally子句,判斷一下引發異常的IL指令代碼是否落入某個finally語句所監視的IL指令範圍之內,CLR據此查找合適的finally語句並執行。

掃描並查找相匹配的finally子句過程是CLR異常處理流程的第二輪。

第二輪的掃描,開始於引發異常的方法,結束於找到異常處理代碼的那一層的方法。然後開始執行異常處理代碼,最後執行上一層的finally語句塊,一直向上執行直到所有finally語句都執行結束。

經過兩輪的掃描之後,CLR就完成了對.NET應用程序引發異常的捕獲與處理工作。

但是,如果CLR並不是每次都能找到合適的異常處理代碼,如果.NET應用程序中沒有定義處理某種異常類型的代碼,而程序運行時又恰好出現此類型的異常,那麼CLR在第一輪掃描時一直上溯到Main方法所包含的異常處理表,然後無功而返。

緊接着CLR會進行第二輪的掃描,執行所有應該被執行的finally語句。在執行了完了finally語句後,CLR將控制權交給操作系統,由它強制中止此進程所創建的所有線程(即使線程本身運行正常),並顯示一個出錯的對話框後結束整個進程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章