为什么ExecuteCodeWithGuaranteedCleanup不起作用?

我试图“测量”堆栈深度。 为什么以下程序不打印任何内容?

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); } } 

如果你想捕获它,将它加载到另一个进程(通过远程处理回调你的进程)并让恶意代码在那里执行。 另一个过程可能会终止,你可以得到一个整洁的SOE突然出现在你身边的管道末端 – 没有相当不方便的例外的不利影响。

请注意,同一进程中的单独AppDomain不会删除它。

如果您想从exception中获取堆栈跟踪,以下代码将为您提供良好的正义:

  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); } } 

关于你的编辑,我不认为抛出StackOverflowException的用户代码与抛出它的CLR相同。

这里有一些关于它的讨论。

Jeffrey(Richter, AppliedMicrosoft®.NETFramework Programming的作者 )注释适用于实际堆栈溢出,即如果您的代码包含无限递归,则会发生堆栈溢出,例如:

void MyMethod(){MyMethod(); }

如果您自己抛出StackOverflowException,它将像任何其他exception一样处理,并且Jeffrey的注释不适用。

此外,杰弗里的评论说:“如果堆栈溢出发生在CLR本身……”。 因此,如果.NET VM可以“干净地”检测到堆栈溢出,即没有将ITSELF运行到堆栈溢出中,那么您应该获得StackOverflowException,并且您的catch和finally块应该像往常一样执行。 但是,在VM ITSELF遇到堆栈溢出的悲惨情况下,您将不会那么幸运:VM不会传播StackOverflowException(但以其他一些奇怪的方式崩溃)并且您的catch和finally块将不会执行。

士气是:小心无限递归,因为你没有100%保证VM会检测并干净地发出信号!

布鲁诺。

澄清了自从OP引用该书以来“杰弗里”是谁。

根据MSDN :

在.NET Framework的早期版本中,您的应用程序可以捕获StackOverflowException对象(例如,从无限制的递归中恢复)。 但是,目前不鼓励这种做法,因为需要大量额外的代码来可靠地捕获堆栈溢出exception并继续执行程序。

从.NET Framework 2.0版开始,try-catch块无法捕获StackOverflowException对象,并且默认情况下会终止相应的进程。 因此,建议用户编写代码以检测并防止堆栈溢出。 例如,如果您的应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。 请注意,承载公共语言运行库(CLR)的应用程序可以指定CLR卸载发生堆栈溢出exception的应用程序域,并让相应的进程继续。 有关更多信息,请参阅ICLRPolicyManager接口和托管公共语言运行时。

由于这个事实,我不相信你能够做你想做的事,因为`StackOverflowException将终止进程。

从.NET Framework 2.0版开始,try-catch块无法捕获StackOverflowException对象,并且默认情况下会终止相应的进程