看看以下两种方法:
public static void foo() {
try {
foo();
} finally {
foo();
}
}
public static void bar() {
bar();
}
Run Code Online (Sandbox Code Playgroud)
运行bar()清楚导致a StackOverflowError,但运行foo()没有(程序似乎只是无限期运行).这是为什么?
我想知道当你试图捕获StackOverflowError时会发生什么,并提出以下方法:
class RandomNumberGenerator {
static int cnt = 0;
public static void main(String[] args) {
try {
main(args);
} catch (StackOverflowError ignore) {
System.out.println(cnt++);
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题:
为什么这个方法打印'4'?
我想也许是因为System.out.println()在调用堆栈上需要3个段,但我不知道3号来自哪里.当你查看源代码(和字节码)时System.out.println(),它通常会导致比3更多的方法调用(因此调用堆栈上的3个段是不够的).如果是因为优化热点VM应用(方法内联),我想知道其他VM上的结果是否会有所不同.
编辑:
由于输出似乎是高度JVM特定的,我使用
Java(TM)SE运行时环境(构建1.6.0_41-b02)
Java HotSpot(TM)64位服务器VM(构建20.14-b01,混合模式)得到结果4
解释为什么我认为这个问题与理解Java堆栈不同:
我的问题不是为什么有一个cnt> 0(显然是因为System.out.println()需要堆栈大小并StackOverflowError在某些东西被打印之前抛出另一个),但为什么它具有特定值4,分别为0,3,8,55或其他的其他东西系统.
我知道无法捕获.NET中的StackOverflowExceptions,删除它们的进程,并且没有堆栈跟踪.这在MSDN上正式记录.但是,我想知道这种行为背后的技术(或其他)原因是什么.所有MSDN都说:
在.NET Framework的早期版本中,您的应用程序可以捕获StackOverflowException对象(例如,从无限递归中恢复).但是,目前不鼓励这种做法,因为需要大量额外的代码来可靠地捕获堆栈溢出异常并继续执行程序.
什么是"重要的附加代码"?这种行为还有其他记录的原因吗?即使我们无法捕获SOE,为什么我们至少不能获得堆栈跟踪?几个同事和我只是沉没几个小时来调试生产StackOverflowException,这可能需要几分钟的堆栈跟踪,所以我想知道我是否有充分的理由让我受苦.