理解Java堆栈

sar*_*oka 28 java stack-overflow exception-handling buffered

有这个代码:

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

还有输出:

1yyyyyyyy2
Run Code Online (Sandbox Code Playgroud)

为什么它打印"y"八次而不再打印.遇到Java println()时如何调用StackOverflowError

mtk*_*mtk 13

在这里你抓住了,Error而不是Exception在哪种情况下你的程序会崩溃.

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

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+"-");

    }
}
}
Run Code Online (Sandbox Code Playgroud)

产量

 1y6869-2
Run Code Online (Sandbox Code Playgroud)

因此,它有stackerror6869次(不同运行的更改),并打印最后一个值.如果您只是y像之前那样打印,那么可能会出现输出缓冲而没有刷新的情况,因为它不是println.


更新

System.out.println内部调用PrintStream该缓冲.您不会从缓冲区中丢失任何数据,它会在填满之后或在您明确调用flush时将所有数据写入输出(在您的情况下为终端).

回到这种情况,它取决于堆栈填充量的内部动态以及能够从catch中执行多少个print语句,doAnything()并且这些字符数被写入缓冲区.在主背面,它最终印有数字2.

javadoc对缓冲流的引用

  • 为什么?我理解PrintStream缓冲,但为什么要去catch块29次? (2认同)

Jav*_*ier 5

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

JLS说:

请注意,由于本机方法执行或Java虚拟机资源限制,可能会通过方法调用以及异步方式同步抛出StackOverflowError.

Java SE平台允许在抛出异步异常之前进行少量但有限的执行.

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