假设程序正在执行该asd()
方法并且堆栈空间即将结束。还假设该方法不是“内部尝试”和“最终内部”,而是打印一个计数器,告诉您堆栈的距离:
void asd(int i){
try{
//inside try block
System.out.print(i);
System.out.println("t");
asd(i+1);
}
finally{
//inside finally
System.out.print(i);
System.out.println("f");
asd(i+1);
}
}
}
现在这就是程序在堆栈空间即将用完时所做的事情,i
即 9154 时。
调用println("t")
输出字符,然后继续调用 println() 方法。这会使程序用尽堆栈空间,因此将执行移至finally
块。打印新行时,对 println 的调用再次耗尽堆栈空间。再次抛出错误,执行移至finally
当前方法调用上方的激活框架中。这使得程序f
第二次打印,因为我们已经从堆栈中弹出一个激活帧,所以这个调用现在正常完成,并打印出一个新行。到目前为止,该程序已给出以下输出:
...
9152t
9153t
9154t9154f9153f // notice we jumped to i=1953
现在,该方法再次调用自身,现在从 finally 块中调用。堆栈空间的情况和之前一样,所以程序执行如上,只是因为我们在一个finally块中进行i=1953的方法调用,所以程序执行结束在方法调用的finally块中我=1952:
9154t9154f9152f
i=9152 的 finally 块asd
再次调用,传递 i=9153,并且由于现在有足够的堆栈空间来打印完整的行,该方法从 try 块输出:
9153t
然后继续调用自身,并且在此调用中将再次耗尽堆栈空间,并给出输出:
9154t9154f9153f
... 其余的输出可以用类似的方式解释:
9154t9154f9151f
9152t
9153t
9154t9154f9153f
9154t9154f9152f
9153t
9154t9154f9153f
9154t9154f9150f
9151t
9152t
9153t
...
需要注意的是:
- 即使在 a 的情况下也会执行 finally 块
StackOverflowError
。
- 运行到 a 的程序
StackOverflowError
可能处于不可预测的状态。println
这里唯一可观察到的效果是不输出换行符的事实。在更复杂的程序中,这可能意味着您不能相信程序正在处理的任何事情的状态,最安全的做法是完全退出。