【问题标题】:Odd Java StackOverflowError?奇怪的Java StackOverflowError?
【发布时间】:2014-03-24 17:32:15
【问题描述】:

为什么这段代码会完全破坏输出?

public class Main {
    public static void main(String[] args) {
        System.out.println();

        rec();
    }

    private static int rec() {
        try {
            return rec();
        } catch(StackOverflowError e) {
            System.out.println("Boo.");
            return 0;
        }
    }
}

我得到的示例输出:Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.

【问题讨论】:

  • 运行代码时,我只得到一个 Boo。
  • 也许试着解释一下你认为这是如何应该起作用的。
  • 它应该只输出Boo.
  • 我的猜测是对 System.out.println 的调用可能会增加堆栈,足以导致 catch 中的另一个堆栈溢出,它会传播到下一个 rec() 调用,再次处理,打印 boo,但会导致另一个 stackoverflow 和另一个 print 等等,直到你有足够的空间 8 个左右的 rec() 调用来捕获异常并没有问题地打印。
  • @NESPowerGlove:“嘘”是有道理的。已打印但没有换行。因此,它无法打印暗示 flush 的换行符,这可能比没有 ln 的简单 print 需要更多的堆栈空间。

标签: java stack-overflow


【解决方案1】:

问题与本题中的问题类似:Stack overflow error handling in finally block

基本上,printlnStackOverflowException 调用您的处理程序会触发进一步的StackOverflowException。这是在对rec() 的封闭调用中处理的。这将继续(在我们进行时展开rec() 调用),直到异常处理程序有足够的空间来完成 println 调用。中间调用可能是将字符添加到输出缓冲区,然后引发 SOE。

准确的解释需要对 PrintStream 和流堆栈的代码进行取证分析......一直到它调用本机代码的地步。


如果您想要一个元解释,那是您的代码正试图从 Error ... 中恢复,javadocs 说这是您不应该尝试做的事情。作为一般规则,在Error 之后,JVM 将处于不确定状态,并且可能会损坏。在这种情况下,不确定性表现为可能已写入或未写入缓冲区的数据。这种行为(可能)是确定性的,但如果没有适当的分析,肯定很难分析,也无法预测。

【讨论】:

  • 是的。 NESPowerGlove 的评论非常明确,如果不是更明确的话。为什么从 main 方法中注释掉 println 会产生影响?
  • 我记得还有一个关于 SO 的问题深入分析了原因,但我找不到:(
  • 感谢您的精彩回答。 :)
猜你喜欢
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多