C#捕获堆栈溢出exception
我得到了一个recursion调用的方法,抛出一个堆栈溢出exception。 第一个调用被try catch块包围,但是exception没有被捕获。
堆栈溢出exception的行为是否有特殊的方式? 我能捕捉/处理exception吗?
注意:如果相关:
-
在主线程中不会抛出exception
-
代码抛出exception的对象由Assembly.LoadFrom(…)。CreateInstance(…)手工加载。
从2.0开始,StackOverflowexception只能在以下情况下被捕获。
- CLR正在宿主环境中运行,主机特别允许处理StackOverflowexception
- 用户代码抛出stackoverflowexception,而不是由于实际的堆栈溢出情况( 参考 )
正确的方法是修复溢出,但….
你可以给自己一个更大的堆栈:
using System.Threading; Thread T = new Thread(threadDelegate, stackSizeInBytes); T.Start();
您可以使用System.Diagnostics.StackTrace FrameCount属性来计算您使用的帧,并在达到帧极限时抛出自己的exception。
或者,您可以计算剩余堆栈的大小,并在低于阈值时抛出您自己的exception: –
class Program { static int n; static int topOfStack; const int stackSize = 1000000; // Default? // The func is 76 bytes, but we need space to unwind the exception. const int spaceRequired = 18*1024; unsafe static void Main(string[] args) { int var; topOfStack = (int)&var; n=0; recurse(); } unsafe static void recurse() { int remaining; remaining = stackSize - (topOfStack - (int)&remaining); if (remaining < spaceRequired) throw new Exception("Cheese"); n++; recurse(); } }
赶上奶酪。 ;)
从StackOverflowException的MSDN页面s:
在以前版本的.NET Framework中,您的应用程序可能会捕获一个StackOverflowException对象(例如,从无限recursion中恢复)。 然而,这种做法目前是不鼓励的,因为需要大量额外的代码才能可靠地捕获堆栈溢出exception并继续执行程序。
从.NET Framework 2.0版开始,StackOverflowException对象不能被try-catch块捕获,相应的进程默认是终止的。 因此,build议用户编写代码来检测和防止堆栈溢出。 例如,如果您的应用程序依赖于recursion,则使用计数器或状态条件来终止recursion循环。 请注意,承载公共语言运行库(CLR)的应用程序可以指定CLR卸载发生堆栈溢出exception的应用程序域,并让相应的进程继续。 有关更多信息,请参阅ICLRPolicyManager接口并承载公共语言运行时。
正如几个用户已经说过的,你无法捕捉到这个exception。 但是,如果您正在努力查找它发生的位置,则可能需要将Visual Studioconfiguration为在投掷时中断。
要做到这一点,你需要从“debugging”菜单打开例外设置。 在旧版本的Visual Studio中,这是在“debugging” – “例外”。 在更新的版本中,它在“debugging” – “Windows” – “exception设置”。
打开设置后,展开“公共语言运行时例外”,展开“系统”,向下滚动并选中“System.StackOverflowException”。 然后,您可以查看调用堆栈并查找重复的调用模式。 这应该让你知道在哪里寻找修复导致堆栈溢出的代码。
是从CLR 2.0堆栈溢出被认为是不可恢复的情况。 所以运行时间仍然closures了这个过程。
有关详细信息,请参阅文档http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx
正如前面提到过的那样,由于进程状态被破坏,系统无法捕获由系统引发的StackOverflowException。 但有一种方法可以将exception作为事件注意到:
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
从.NET Framework版本4开始,除非事件处理程序对安全至关重要,并且具有HandleProcessCorruptedStateExceptionsAttribute特性,否则不会引发此事件,以处理损坏进程状态(例如堆栈溢出或访问冲突)的exception。
然而,你的应用程序将退出事件function后终止(一个非常肮脏的解决方法,是重新启动应用程序在这个事件哈哈,havn't这样做,永远不会做)。 但是,logging就够了!
在.NET Framework版本1.0和1.1中,发生在主应用程序线程以外的线程中的未处理的exception被运行时捕获,因此不会导致应用程序终止。 因此,在应用程序终止的情况下,可能引发UnhandledException事件。 从.NET Framework 2.0版开始,删除了子线程中未处理的exception的反向支持,因为这种静默失败的累积影响包括性能下降,数据损坏和locking,所有这些都难以debugging。 有关更多信息(包括运行时未终止的情况列表),请参阅托pipe线程中的例外。
你不能。 CLR不会让你。 堆栈溢出是致命的错误,无法从中恢复。
你不能像大多数的post解释,让我再添加一个领域:
在许多网站上,你会发现有人说,避免这种情况的方法是使用不同的AppDomain,所以如果发生这种情况,域将被卸载。 这是绝对错误的(除非你托pipe你的CLR),因为CLR的默认行为将引发一个KillProcess事件,从而导致你的默认AppDomain。
这是不可能的,并有一个很好的理由(一个,想想所有这些捕获(例外){}周围)。
如果要在堆栈溢出后继续执行,请在另一个AppDomain中运行危险代码。 可以将CLR策略设置为终止当前AppDomain溢出而不影响原始域。