C# 捕获堆栈溢出异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1599219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# catch a stack overflow exception
提问by Toto
I have a recursive call to a method that throws a stack overflow exception. The first call is surrounded by a try catch block but the exception is not caught.
我对一个抛出堆栈溢出异常的方法进行了递归调用。第一个调用被 try catch 块包围,但未捕获异常。
Does the stack overflow exception behave in a special way? Can I catch/handle the exception properly?
堆栈溢出异常是否以特殊方式运行?我可以正确捕获/处理异常吗?
Not sure if relevant, but additional information:
不确定是否相关,但附加信息:
the exception is not thrown in the main thread
the object where the code is throwing the exception is manually loaded by Assembly.LoadFrom(...).CreateInstance(...)
异常不会在主线程中抛出
代码抛出异常的对象由 Assembly.LoadFrom(...).CreateInstance(...) 手动加载
采纳答案by JaredPar
Starting with 2.0 a StackOverflow Exception can only be caught in the following circumstances.
从 2.0 开始,只能在以下情况下捕获 StackOverflow 异常。
- The CLR is being run in a hosted environment*where the host specifically allows for StackOverflow exceptions to be handled
- The stackoverflow exception is thrown by user code and not due to an actual stack overflow situation (Reference)
- CLR 正在托管环境中运行*在该环境中,主机专门允许处理 StackOverflow 异常
- stackoverflow 异常是由用户代码抛出的,而不是由于实际的堆栈溢出情况(参考)
*"hosted environment" as in "my code hosts CLR and I configure CLR's options" and not "my code runs on shared hosting"
*“托管环境”如“我的代码托管 CLR 和我配置 CLR 的选项”而不是“我的代码在共享托管上运行”
回答by Brian Rasmussen
Yes from CLR 2.0 stack overflow is considered a non-recoverable situation. So the runtime still shut down the process.
是从 CLR 2.0 堆栈溢出被认为是不可恢复的情况。所以运行时仍然关闭进程。
For details please see the documentation http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx
有关详细信息,请参阅文档http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx
回答by Damien_The_Unbeliever
From the MSDN page on StackOverflowExceptions:
从StackOverflowException上的 MSDN 页面:
In prior versions of the .NET Framework, your application could catch a StackOverflowException object (for example, to recover from unbounded recursion). However, that practice is currently discouraged because significant additional code is required to reliably catch a stack overflow exception and continue program execution.
Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. Note that an application that hosts the common language runtime (CLR) can specify that the CLR unload the application domain where the stack overflow exception occurs and let the corresponding process continue. For more information, see ICLRPolicyManager Interface and Hosting the Common Language Runtime.
在 .NET Framework 的早期版本中,您的应用程序可以捕获 StackOverflowException 对象(例如,从无界递归中恢复)。但是,目前不鼓励这种做法,因为需要大量额外代码才能可靠地捕获堆栈溢出异常并继续执行程序。
从 .NET Framework 2.0 版开始,一个 StackOverflowException 对象不能被 try-catch 块捕获,相应的进程默认终止。因此,建议用户编写他们的代码来检测和防止堆栈溢出。例如,如果您的应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。请注意,承载公共语言运行库 (CLR) 的应用程序可以指定 CLR 卸载发生堆栈溢出异常的应用程序域,并让相应的进程继续进行。有关更多信息,请参阅 ICLRPolicyManager 接口和托管公共语言运行时。
回答by Matthew Scharley
You can't. The CLR won't let you. A stack overflow is a fatal error and can't be recovered from.
你不能。CLR 不会让你。堆栈溢出是致命错误,无法恢复。
回答by ima
It's impossible, and for a good reason (for one, think about all those catch(Exception){} around).
这是不可能的,并且有充分的理由(首先,考虑一下所有这些 catch(Exception){} 周围)。
If you want to continue execution after stack overflow, run dangerous code in a different AppDomain. CLR policies can be set to terminate current AppDomain on overflow without affecting original domain.
如果您想在堆栈溢出后继续执行,请在不同的 AppDomain 中运行危险代码。CLR 策略可以设置为在溢出时终止当前 AppDomain,而不影响原始域。
回答by Simon
As several users have already said, you can't catch the exception. However, if you're struggling to find out where it's happening, you may want to configure visual studio to break when it's thrown.
正如一些用户已经说过的那样,您无法捕获异常。但是,如果您正在努力找出它发生的位置,您可能需要将 Visual Studio 配置为在抛出时中断。
To do that, you need to open Exception Settings from the 'Debug' menu. In older versions of Visual Studio, this is at 'Debug' - 'Exceptions'; in newer versions, it's at 'Debug' - 'Windows' - 'Exception Settings'.
为此,您需要从“调试”菜单中打开“异常设置”。在旧版本的 Visual Studio 中,这是在“调试”-“异常”处;在较新的版本中,它位于“调试”-“Windows”-“异常设置”。
Once you have the settings open, expand 'Common Language Runtime Exceptions', expand 'System', scroll down and check 'System.StackOverflowException'. Then you can look at the call stack and look for the repeating pattern of calls. That should give you an idea of where to look to fix the code that's causing the stack overflow.
打开设置后,展开“公共语言运行时异常”,展开“系统”,向下滚动并检查“System.StackOverflowException”。然后您可以查看调用堆栈并查找调用的重复模式。这应该让您知道在哪里可以修复导致堆栈溢出的代码。
回答by Simon
The right way is to fix the overflow, but....
正确的方法是修复溢出,但是......
You can give yourself a bigger stack:-
你可以给自己一个更大的筹码:-
using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();
You can use System.Diagnostics.StackTrace FrameCount property to count the frames you've used and throw your own exception when a frame limit is reached.
您可以使用 System.Diagnostics.StackTrace FrameCount 属性来计算您使用的帧数,并在达到帧数限制时抛出您自己的异常。
Or, you can calculate the size of the stack remaining and throw your own exception when it falls below a threshold:-
或者,您可以计算剩余堆栈的大小并在低于阈值时抛出您自己的异常:-
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();
}
}
Just catch the Cheese. ;)
只要抓住奶酪。;)
回答by No hay Problema
You can't as most of the posts are explaining, let me add another area:
您不能像大多数帖子所解释的那样,让我添加另一个区域:
On many websites you will find people saying that the way to avoid this is using a different AppDomain so if this happens the domain will be unloaded. That is absolutely wrong (unless you host your CLR) as the default behavior of the CLR will raise a KillProcess event, bringing down your default AppDomain.
在许多网站上,您会发现人们说避免这种情况的方法是使用不同的 AppDomain,因此如果发生这种情况,该域将被卸载。这是绝对错误的(除非您托管您的 CLR),因为 CLR 的默认行为会引发 KillProcess 事件,从而关闭您的默认 AppDomain。
回答by FooBarTheLittle
As mentioned above several times, it's not possible to catch a StackOverflowException that was raised by the System due to corrupted process-state. But there's a way to notice the exception as an event:
如上所述,由于进程状态损坏,无法捕获系统引发的 StackOverflowException。但是有一种方法可以将异常视为事件:
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspxStarting with the .NET Framework version 4, this event is not raised for exceptions that corrupt the state of the process, such as stack overflows or access violations, unless the event handler is security-critical and has the HandleProcessCorruptedStateExceptionsAttribute attribute.
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx从 .NET Framework 版本 4 开始,对于破坏进程状态的异常(例如堆栈溢出或访问冲突),不会引发此事件,除非事件处理程序对安全性至关重要并且具有 HandleProcessCorruptedStateExceptionsAttribute 属性。
Nevertheless your application will terminate after exiting the event-function (a VERY dirty workaround, was to restart the app within this event haha, havn't done so and never will do). But it's good enough for logging!
尽管如此,您的应用程序将在退出事件函数后终止(一个非常肮脏的解决方法,是在此事件中重新启动应用程序哈哈,还没有这样做,也永远不会这样做)。但它足以记录日志!
In the .NET Framework versions 1.0 and 1.1, an unhandled exception that occurs in a thread other than the main application thread is caught by the runtime and therefore does not cause the application to terminate. Thus, it is possible for the UnhandledException event to be raised without the application terminating. Starting with the .NET Framework version 2.0, this backstop for unhandled exceptions in child threads was removed, because the cumulative effect of such silent failures included performance degradation, corrupted data, and lockups, all of which were difficult to debug. For more information, including a list of cases in which the runtime does not terminate, see Exceptions in Managed Threads.
在 .NET Framework 1.0 和 1.1 版中,在主应用程序线程以外的线程中发生的未处理异常会被运行时捕获,因此不会导致应用程序终止。因此,有可能在不终止应用程序的情况下引发 UnhandledException 事件。从 .NET Framework 2.0 版开始,删除了子线程中未处理异常的这种支持,因为此类静默故障的累积影响包括性能下降、数据损坏和锁定,所有这些都难以调试。有关更多信息,包括运行时未终止的情况列表,请参阅托管线程中的异常。