我试图“测量”堆栈深度。以下程序为什么不打印任何内容?
class Program
{
private static int Depth = 0;
static void A(object o)
{
Depth++;
A(o);
}
static void B(object o, bool e)
{
Console.WriteLine(Depth);
}
static void Main(string[] args)
{
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
}
}
有些答案只包含来自MSDN的引用,例如“从.NET Framework 2.0版开始,无法通过try-catch块捕获StackOverflowException对象,并且默认情况下会终止相应的进程。”相信我,有时(当有足够的堆栈空间时)它可以是cought,下面打印一些数字就好了:
class Program
{
private static int depth = 0;
static void A(object o)
{
depth++;
if (Environment.StackTrace.Length > 8000)
throw new StackOverflowException("Catch me if you can.");
A(o);
}
static void B(object o, bool e)
{
Console.WriteLine(depth);
}
static void Main(string[] args)
{
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
}
}
答案 0 :(得分:6)
关于你的编辑,我不认为抛出StackOverflowException的用户代码与抛出它的CLR相同。
有一些关于它的讨论here。
杰弗里(Richter,Applied Microsoft® .NET Framework Programming的作者)评论适用于实际堆栈溢出,即堆栈溢出 如果您的代码包含无限递归,则会发生这种情况,例如:void MyMethod(){MyMethod(); }
如果你扔了 StackOverflowException自己,它 将像其他任何一样处理 例外,杰弗里的评论确实如此 不适用。
此外,杰弗里的评论说:“如果 在CLR内发生堆栈溢出 自己...“。所以,如果.NET VM可以 检测堆栈溢出“干净”, 即没有将ITSELF运行到 堆栈溢出,然后你应该得到一个 StackOverflowException和你的捕获 最后块应该执行为 通常。但是,在悲惨的情况下 VM ITSELF进入堆栈 溢出,你不会那么幸运: VM不会传播 StackOverflowException(但崩溃了 一些其他奇怪的方式)和你的捕获 最后块不会执行。
士气是:小心无限 递归,因为你没有 100%保证VM将检测到 并清楚地发出信号!
布鲁诺。
澄清了自从OP引用该书以来“杰弗里”是谁。
答案 1 :(得分:5)
如果你想捕获它,将它加载到另一个进程(通过远程处理回调你的进程)并让恶意代码在那里执行。另一个过程可能会终止,你可以得到一个整洁的SOE弹出管道末端 - 没有相当不方便的例外的不利影响。
请注意,同一进程中的单独AppDomain不会删除它。
如果您想从异常中获取堆栈跟踪,以下代码将为您提供良好的正义:
class Program
{
static void Main(string[] args)
{
try
{
Recurse(0);
}
catch (Exception ex)
{
StackTrace st = new StackTrace(ex);
// Go wild.
Console.WriteLine(st.FrameCount);
}
Console.ReadLine();
}
static void Recurse(int counter)
{
if (counter >= 100)
throw new Exception();
Recurse(++counter);
}
}
答案 2 :(得分:3)
根据MSDN:
在.NET的早期版本中 框架,您的应用程序可以 捕获StackOverflowException对象 (例如,从中恢复 无限递归)。但是,那 目前不鼓励练习 因为重要的额外代码是 需要可靠地捕获堆栈 溢出异常并继续 程序执行。
从.NET Framework开始 版本2.0,StackOverflowException try-catch无法捕获对象 块和相应的过程是 默认终止。所以, 建议用户编写代码 检测和防止堆栈 溢出。例如,如果你的 应用程序取决于递归,使用 反击或国家条件 终止递归循环。注意 托管的应用程序 公共语言运行库(CLR)可以 指定CLR卸载 应用程序域所在的堆栈 溢出异常发生并让 相应的过程继续。对于 更多信息,请参阅 ICLRPolicyManager接口和 托管公共语言运行时。
由于这个事实,我不相信你能做你想做的事,因为`StackOverflowException将终止进程。
答案 3 :(得分:0)
从.NET Framework 2.0版开始,try-catch块无法捕获StackOverflowException对象,默认情况下会终止相应的进程