我有一个递归调用一个引发堆栈溢出异常的方法。第一次调用被try catch块包围,但未捕获异常。
堆栈溢出异常是否以特殊方式表现?我可以正确捕获/处理异常吗?
不确定是否相关,但还有其他信息:
在主线程中没有抛出异常
代码引发异常的对象由Assembly.LoadFrom(...)。CreateInstance(...)手动加载
Assert.Fail
改为。如此认真-我们该如何处理?
我有一个递归调用一个引发堆栈溢出异常的方法。第一次调用被try catch块包围,但未捕获异常。
堆栈溢出异常是否以特殊方式表现?我可以正确捕获/处理异常吗?
不确定是否相关,但还有其他信息:
在主线程中没有抛出异常
代码引发异常的对象由Assembly.LoadFrom(...)。CreateInstance(...)手动加载
Assert.Fail
改为。如此认真-我们该如何处理?
Answers:
从2.0版本开始,只能在以下情况下捕获StackOverflow异常。
* “托管环境”,如“我的代码托管CLR,并且我配置CLR的选项”中那样,而不是“我的代码在共享托管上运行”中
Starting with 2.0 ...
,我是老客户,是什么阻止了他们捕获SO,又有什么可能的方式1.1
(您在评论中提到了这一点)?
正确的方法是解决溢出问题,但是...
您可以给自己更大的筹码:-
using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();
您可以使用System.Diagnostics.StackTrace FrameCount属性对已使用的帧进行计数,并在达到帧数限制时抛出自己的异常。
或者,您可以计算剩余堆栈的大小,并在低于阈值时引发自己的异常:-
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();
}
}
赶上奶酪。;)
Cheese
还远远不够。我会去throw new CheeseException("Gouda");
在StackOverflowException的MSDN页面上:
在.NET Framework的早期版本中,您的应用程序可能会捕获StackOverflowException对象(例如,从无限制的递归中恢复)。但是,目前不建议采用这种做法,因为需要大量额外的代码才能可靠地捕获堆栈溢出异常并继续执行程序。
从.NET Framework 2.0版开始,try-catch块无法捕获StackOverflowException对象,并且默认情况下终止了相应的进程。因此,建议用户编写其代码以检测并防止堆栈溢出。例如,如果您的应用程序依赖于递归,请使用计数器或状态条件终止递归循环。请注意,承载公共语言运行时(CLR)的应用程序可以指定CLR卸载发生堆栈溢出异常的应用程序域,并继续进行相应的处理。有关更多信息,请参见ICLRPolicyManager界面和托管公共语言运行时。
正如几个用户已经说过的那样,您无法捕获异常。但是,如果您想弄清楚它在哪里发生,则可能需要配置Visual Studio,使其在抛出时中断。
为此,您需要从“调试”菜单中打开“例外设置”。在旧版本的Visual Studio中,此位置为“调试”-“异常”;在较新版本中,它位于“调试”-“ Windows”-“异常设置”中。
打开设置后,展开“公共语言运行时异常”,展开“系统”,向下滚动并检查“ System.StackOverflowException”。然后,您可以查看调用堆栈并查找重复的调用模式。那应该给你一个思路,去寻找导致堆栈溢出的代码。
如上所述,由于进程状态已损坏,无法捕获由系统引发的StackOverflowException。但是有一种方法可以将异常视为事件:
http://msdn.microsoft.com/zh-CN/library/system.appdomain.unhandledexception.aspx从.NET Framework版本4开始,除非破坏事件处理程序的安全性至关重要并且具有HandleProcessCorruptedStateExceptionsAttribute属性,否则不会引发破坏进程状态的异常(例如堆栈溢出或访问冲突)的事件。
不过,您的应用程序将在退出事件功能后终止(一个非常肮脏的解决方法,是在此事件中重新启动应用程序,哈哈,从未这样做,也永远不会这样做)。但这足以记录日志!
在.NET Framework版本1.0和1.1中,运行时会捕获在主应用程序线程以外的线程中发生的未处理异常,因此不会导致应用程序终止。因此,有可能在不终止应用程序的情况下引发UnhandledException事件。从.NET Framework 2.0版开始,删除了针对子线程中未处理异常的支持,因为此类静默故障的累积影响包括性能下降,数据损坏和锁定,所有这些都难以调试。有关更多信息,包括运行时未终止的情况的列表,请参阅托管线程中的异常。
是CLR 2.0堆栈溢出被认为是不可恢复的情况。因此,运行时仍会关闭进程。
有关详细信息,请参阅文档http://msdn.microsoft.com/zh-cn/library/system.stackoverflowexception.aspx
StackOverflowException
中,默认情况下会终止该过程。
你不能 CLR不允许您这样做。堆栈溢出是一个致命错误,无法从中恢复。
这是不可能的,并且有充分的理由(其中一个原因,请考虑一下所有这些catch(Exception){})。
如果要在堆栈溢出后继续执行,请在其他AppDomain中运行危险代码。可以将CLR策略设置为在溢出时终止当前AppDomain,而不会影响原始域。