了解 Java 堆栈

有以下代码:

public class Main {
    public static void main(final String[] args) throws Exception {
        System.out.print("1");
        doAnything();
        System.out.println("2");
    }

    private static void doAnything() {
        try {
            doAnything();
        } catch (final Error e) {
            System.out.print("y");
        }
    }
}

还有输出:

1yyyyyyyy2

为什么它打印“y”八次而没有更多。遇到 Java 时如何调用?println()StackOverflowError


答案 1

在这里,您正在捕获,而不是在这种情况下,您的程序会崩溃。ErrorException

如果尝试此代码(已修改以添加静态计数器)

public class StackError {

static int i = 1;

public static void main(final String[] args) throws Exception {
    System.out.print("1");
    doAnything();
    System.out.println("2");
}

private static void doAnything() {
    try {
        i++;
//          System.out.println(i);
        doAnything();
    } catch (Error e) {
        System.out.print("y"+i+"-");

    }
}
}

输出

 1y6869-2

因此,它有6869次(不同运行的变化),最后一个值被打印出来。如果您只是像之前那样打印,则可能会出现输出被缓冲而未被刷新的情况,因为它不是 .stackerroryprintln


更新

内部调用已缓冲的。您不会从缓冲区中丢失任何数据,在缓冲区填满后,或者当您显式调用 flush 时,它会全部写入输出(在您的情况下是终端)。System.out.printlnPrintStream

回到此方案,这取决于堆栈已填充量的内部动态,能够从 catchin 执行的打印语句数,以及写入缓冲区的字符数。在主背面,它印有数字。doAnything()2

对缓冲流的 javadoc 引用


答案 2

我敢打赌,通过在捕获块中调用,您可以强制另一个被外部块捕获的块。其中一些调用没有足够的堆栈来实际写入输出流。printStackOverflowError

JLS说:

请注意,StackOverflowError 可能通过方法调用同步引发,也可能由于本机方法执行或 Java 虚拟机资源限制而异步引发。

Java SE 平台允许在引发异步异常之前发生少量但有限制的执行量。

允许上面提到的延迟允许优化的代码在遵守Java编程语言语义的同时处理这些异常的点上检测并抛出这些异常。一个简单的实现可能会在每个控制传输指令的点上轮询异步异常。由于程序的大小有限,因此这为检测异步异常的总延迟提供了限制。


推荐