递归调用期间的StackOverflowError

时间:2014-09-01 17:01:58

标签: java

这个问题严格来说是理论上的,但我无法找到答案。考虑这个简短的程序:

public class SBtst {

    int i = 0;

    public static void main(String[] args) {
        new SBtst().rec();
    }

    public void rec() {
        System.out.println("rec is called "+i++);
        try {
            rec();
        } catch (StackOverflowError soe) {
            System.out.println("completed "+soe.getStackTrace().length);
        }
    }

}

执行后,我得到的输出类似于:

rec is called 10472
rec is called 10473
rec is called 10474Recursion completed 1024

问题是:

  1. 为什么没有println()完成新行,因为根据我的理解,当执行下一个rec()调用时它应该抛出一个错误,并且它是在完成后的println()

  2. 为什么我只在stackTrace数组中获得1024个元素,但i等于10474?这是否意味着并非所有呼叫都在堆栈跟踪中?

1 个答案:

答案 0 :(得分:8)

第1部分:

the OpenJDK implementation中,println()实现如下:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

因此,对print(x)的调用可能会溢出堆栈,并且StackOverflowError将在没有调用newLine()方法的情况下被提升。

第2部分:

来自Java API

  

在某些情况下,某些虚拟机可能会从堆栈跟踪中省略一个或多个堆栈帧...一般来说,此方法返回的数组将包含每个将由printStackTrace打印的帧的元素。

因此,JVM可以自由地对堆栈跟踪中存储的堆栈帧数施加限制,例如1024.