这个问题在这里已有答案:
根据Oracle的说法,StackOverflowError是:
发生堆栈溢出时抛出,因为应用程序过于严重 .
我知道递归是什么,通常递归函数,如果没有正确终止,会导致StackOverflowError . 要检查在抛出 StackOverflowError
之前发生的递归调用的数量,我编写了以下代码:
package ErrorCases;
public class StackOverFlowError {
static int i=0;
void a()
{
//System.out.println("called "+(++i));
try{
++i;
a();
}catch(Error e)
{
System.out.println(e.getClass());
System.out.println(i);
}
}
public static void main(String[] args) {
new StackOverFlowError().a();
}
}
i
的值给出了在JVM抛出StackOverflowError之前递归调用 a()
的计数 .i
的值在每次运行中都不同,如:
output 1: class java.lang.StackOverflowError
10466
Output 2: class java.lang.StackOverflowError
10470
My query is ?
-
在JVM抛出
StackOverflowError
之前递归的深度有多大? -
一旦
StackOverflowError
被抛出,我们可以恢复吗?
4 回答
深度取决于两件事:
1:堆栈的大小 .
2:每次递归中使用的堆栈空间量 .
函数参数,局部变量和返回地址都在堆栈上分配,而对象在堆上分配 .
Recovery
有可能恢复 .
但是,请注意以下有关错误的信息(来自java API doc):
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
EDIT:
注意事项:虽然在递归函数中捕获异常是可以的,但不要试图捕获错误 . 如果堆栈已满,则错误处理将导致新错误 . 简单的事情,例如对
System.out.println()
的调用将失败,因为堆栈上没有剩余空间用于返回地址 .这就是错误应该在递归函数之外捕获的原因 .
这实际上取决于您正在使用的机器以及您的JVM及其配置 . (在我目前的设置中它是6000 - 8500,后台有很多任务)最多,这是你在应用程序和递归方法中所做的 .
没有!我Java抛出一个错误,没有办法恢复正常 . 这是例外和错误之间的主要区别 .
Read more about Errors here
Read more about Java stack size myths here
Edit:
发生错误后你仍然可以做一些事情,但它有意义吗?您的代码中存在严重错误!你无法确定一切正常!
您的代码没有终止,因为您再次调用该方法,就像无限循环一样
您可能会看到不同堆栈深度的原因是堆栈帧的大小不一定相同 . 例如,Hotspot JVM具有用于JIT编译代码和解释代码的不同堆栈帧 . JIT编译器与正在运行的代码并行工作,因此外部因素(如机器上的负载)可能会影响JVM何时/是否开始使用JIT堆栈帧 .
你应该记住的一件事是,当你得到一个
StackOverflowError
时,你所做的几乎任何事情都可能导致另一个StackOverflowError
. 例如,在catch
部分中打印错误类的名称也可能会耗尽堆栈空间,因此另一个StackOverflowError
将被抛出堆栈 .有些人声称你无法从
Error
恢复,因为JVM正在关闭 . 这不正确;你可以从一些错误中恢复 . 关于StackOverflowError
和OutOfMemoryError
的一个棘手问题是,一旦你找到了一个,你绝对不能保证程序的状态;例如,您使用的密钥数据结构可能处于不一致状态 . 这使得恢复一般很难或不可能 .参数和局部变量在堆栈上分配(对象存在于堆上的引用类型和引用该对象的变量) . 堆栈通常位于地址空间的上端,当它用完时,它朝向地址空间的底部(即朝向零) .
您的进程还有一个堆,它位于流程的底端 . 在分配内存时,此堆可以向地址空间的上端增长 . 正如你所看到的那样,堆栈有可能与堆栈(有点像技术板块!!!) . [source]
因此,StackOIverflowError将取决于您的堆栈大小以及堆大小,这将取决于执行到执行,因为GC等很多因素 .
此外,正如名称所说,它是错误而不是异常 . 没有恢复它 . JVM将关闭 .