2011-09-20 129 views
5

如果我這樣寫:爲什麼.NET不爲StackOverflow異常記錄堆棧跟蹤?

class Program 
{ 
    static void Main(string[] args) 
    { 
     throw new Exception("lol"); 
    } 
} 

,並運行在命令行的EXE,我得到了我的事件日誌中的兩個項目。一個是應用程序錯誤,表示存在未處理的異常,另一個包含堆棧跟蹤,源爲.NET運行時。

如果我這樣寫:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Recurse4Evr(); 
    } 

    static void Recurse4Evr() 
    { 
     Recurse4Evr(); 
    } 
} 

我只得到我的事件日誌,它說應用程序錯誤的一個條目,並且有一個堆棧溢出異常。堆棧跟蹤沒有第二個條目,所以它基本上沒用。

爲什麼不記錄堆棧跟蹤?如果我設置DebugDiag並將其附加到我的進程,然後出現堆棧溢出,DebugDiag可以記錄堆棧跟蹤。很顯然,堆棧跟蹤以某種方式可用於外部世界。如果運行時正在終止進程,因爲它檢測到了堆棧溢出,那麼它也知道堆棧是什麼。

在有許多複雜交互的大型應用程序中,通常不可能重新創建導致堆棧溢出的條件。在這種情況下,堆棧跟蹤是瞭解發生情況的唯一方法。爲什麼微軟決定記錄這些信息並不重要?有沒有一個合理的設計決定不明顯?

+4

我的猜測是生成堆棧跟蹤進程需要函數調用,因爲堆棧溢出而無法工作。調試器通過能夠使用自己的數據結構和(有希望)健康的堆棧來遍歷堆棧。 – siride

+0

這是一個很好的問題!我不知道它是否與檢測堆棧溢出的方式有關......在.Net 2.0之後,似乎你也無法捕獲它,所以它看起來好像是按照一組特殊的規則來玩。 –

+0

[C#捕獲堆棧溢出異常]的可能重複(http://stackoverflow.com/questions/1599219/c-catch-a-stack-overflow-exception) – balexandre

回答

0

這顯然是不可能的。如果你想要一個堆棧跟蹤,以便找到殺死你的應用程序的有害代碼,你需要附加一個第三方工具,如DebugDiag或AdsPlus。祝你好運,基本上沒有這些工具的文檔。

1

堆棧溢出被認爲是不可恢復的情況,因此運行時會終止進程。

總結:

from Damien_The_Unbeliever

從MSDN頁面上StackOverflowException S:

在.NET Framework的早期版本中,您的應用程序可以趕上一個StackOverflowException對象(例如,從無限遞歸中恢復)。然而,這種做法目前令人沮喪,因爲需要大量額外的代碼才能可靠地捕獲堆棧溢出異常並繼續執行程序。

從.NET Framework 2.0版開始,StackOverflowException對象不能被try-catch塊捕獲,並且相應的進程默認終止。因此,建議用戶編寫代碼來檢測和防止堆棧溢出。例如,如果您的應用程序依賴於遞歸,請使用計數器或狀態條件來終止遞歸循環。請注意,承載公共語言運行庫(CLR)的應用程序可以指定CLR卸載發生堆棧溢出異常的應用程序域,並讓相應的進程繼續。有關更多信息,請參閱ICLRPolicyManager接口並承載公共語言運行時。


from JaredPar

與2.0開始出現StackOverflow異常只能在下列情況下被捕獲。

  1. CLR是在宿主環境中,其中主機特別允許的StackOverflow例外處理
  2. 該計算器異常是由用戶代碼拋出,而不是由於實際的堆棧溢出情況中運行(Reference
+0

我不想抓到它。我問爲什麼當你的程序終止時,以及運行時日誌記錄事件日誌中有錯誤,爲什麼它不包括堆棧跟蹤。 – dan

+0

也,我認爲微軟的「建議」是非常簡單的。當然,這對遞歸算法是有意義的 - 當然你應該以迭代的方式寫斐波納契。我的情況不是遞歸算法,在異常事件處理程序中的記錄器中有錯誤。記錄器投擲,然後再次觸發事件處理程序,它再次拋出等。我只能使用DebugDiag找到導致溢出的原因。微軟的建議基本上是「不要編寫有bug的代碼」。 – dan

相關問題