我有一个递归调用的方法,会抛出堆栈溢出异常。第一次调用被try catch块包围,但异常未被捕获。
堆栈溢出异常是否有特殊的行为?我能否正确地捕获/处理异常?
不确定是否相关,但需要注意以下信息:
异常并没有在主线程中抛出
代码抛出异常的对象是由Assembly.LoadFrom(...).CreateInstance(...)手动加载的
我有一个递归调用的方法,会抛出堆栈溢出异常。第一次调用被try catch块包围,但异常未被捕获。
堆栈溢出异常是否有特殊的行为?我能否正确地捕获/处理异常?
不确定是否相关,但需要注意以下信息:
异常并没有在主线程中抛出
代码抛出异常的对象是由Assembly.LoadFrom(...).CreateInstance(...)手动加载的
从2.0版本开始,只有在以下情况下才能捕获堆栈溢出异常:
*“托管环境”指“我的代码托管CLR并配置CLR的选项”而不是“我的代码在共享主机上运行”
正确的方法是修复溢出,但是....
您可以为自己分配更大的堆栈:
using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();
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页面中可以得知:
在之前版本的.NET Framework中,应用程序可以捕获StackOverflowException对象(例如,为了从无限递归中恢复)。然而,目前不鼓励这种做法,因为需要编写更多代码来可靠地捕获堆栈溢出异常并继续程序执行。
从.NET Framework 2.0开始,无法使用try-catch块捕获StackOverflowException对象,默认情况下对应的进程会被终止。因此,建议用户编写代码以检测和防止堆栈溢出。例如,如果应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。注意,托管公共语言运行时(CLR)的应用程序可以指定CLR卸载发生堆栈溢出异常的应用程序域,并让相应进程继续运行。有关更多信息,请参阅ICLRPolicyManager接口和托管公共语言运行时。
正如其他用户所说,你无法捕获异常。 但是,如果你正在努力找出异常发生的位置,可以配置Visual Studio在异常抛出时中断。
要做到这一点,需要从“调试”菜单中打开“异常设置”。 在较旧版本的Visual Studio中,这位于“调试” - “异常”;在较新版本中,它位于“调试” - “Windows” - “异常设置”。
打开设置后,展开“公共语言运行时异常”,展开“系统”,向下滚动并选中“System.StackOverflowException”。然后您可以查看调用堆栈并查找重复调用模式。 这应该让您知道在哪里修复导致堆栈溢出的代码。
多次提到过,由于进程状态损坏导致的 StackOverflowException 是无法被 System 捕获的。但有一种方法可以将其作为事件来检测:
http://msdn.microsoft.com/en-us/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/en-us/library/system.stackoverflowexception.aspx
StackOverflowException
会终止进程。 - Brian Rasmussen正如大部分帖子所解释的那样,你不能这样做,我再补充一个方面:
在许多网站上,您会发现有人说避免这种情况的方法是使用不同的AppDomain,这样如果发生这种情况,该域将被卸载。但这是绝对错误的(除非您托管 CLR),因为CLR的默认行为会引发KillProcess事件,关闭您的默认AppDomain。
你不行,CLR 不会让你这么做。栈溢出是致命错误,无法从中恢复。
这是不可能的,也有很好的原因(例如,请考虑所有那些catch(Exception){})。
如果您想在堆栈溢出后继续执行代码,请在不同的AppDomain中运行危险代码。CLR策略可以设置为在溢出时终止当前AppDomain而不影响原始域。
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
try
{
Recursion();
}
catch (InsufficientExecutionStackException e)
{
}
}
static void Recursion()
{
RuntimeHelpers.EnsureSufficientExecutionStack();
Recursion();
}
}
Assert.Fail
。那么严肃地说--我们该如何解决这个问题? - BrainSlugs83