StackOverflowError何时发生?

时间:2013-12-18 12:29:57

标签: java recursion stack stack-overflow

根据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();

   }

}

{J}抛出StackOverflowError之前,i的值给出了a()的递归调用计数。 i的值在每次运行中都不同,如:

output 1: class java.lang.StackOverflowError
           10466
Output 2: class java.lang.StackOverflowError
           10470

我的查询是?

  1. 在JVM抛出之前递归的深度 StackOverflowError

  2. StackOverflowError可以恢复一次     被抛出?

4 个答案:

答案 0 :(得分:6)

深度取决于两件事:

1:堆栈的大小。

2:每次递归中使用的堆栈空间量。

在堆上分配对象时,函数参数,局部变量和返回地址都在堆栈上分配。

<强>恢复

可以恢复。

try {
    myDeepRecursion();
} catch (StackOverflowError e) {
  // We are back from deep recursion. Stack should be ok again.
}

但是,请注意以下有关错误的信息(来自java API文档):

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

编辑:

注意事项:在递归函数中捕获异常是可以的,不要试图捕获错误。如果堆栈已满,则错误处理将导致新错误。简单的事情,例如对System.out.println()的调用将失败,因为堆栈上没有剩余空间用于返回地址。

这就是错误应该在递归函数之外捕获的原因。

答案 1 :(得分:3)

  

在JVM抛出StackOverflowError之前,递归有多深?

这实际上取决于您正在使用的计算机以及您的JVM及其配置。 (在我当前的设置中它是6000 - 8500,后台有很多任务)最多,这是你在应用程序和递归方法中所做的。

  

一旦抛出StackOverflowError,我们可以恢复吗?

没有!我Java抛出一个错误,没有办法恢复正常。这是例外和错误之间的主要区别。

  

错误是Throwable的子类,表示合理的应用程序不应该尝试捕获的严重问题

Read more about Errors here

Read more about Java stack size myths here

修改

发生错误后你仍然可以做某事,但这有意义吗?您的代码中存在严重错误!你无法确定一切正常!

您的代码没有终止,因为您再次调用该方法,就像无限循环一样

答案 2 :(得分:2)

您可能会看到不同堆栈深度的原因是堆栈帧的大小不一定相同。例如,Hotspot JVM具有用于JIT编译代码和解释代码的不同堆栈帧。 JIT编译器与正在运行的代码并行工作,因此机器上的负载等外部因素可能会影响JVM何时/如果开始使用JIT堆栈帧。

你应该记住的一件事是,当你得到一个StackOverflowError时,你所做的几乎任何事情都可能导致另一个StackOverflowError。例如,打印catch部分中错误类的名称也可能会耗尽堆栈空间,因此另一个StackOverflowError将被抛出堆栈。

有些人声称您无法从Error恢复,因为JVM正在关闭。这不正确;你可以从一些错误中恢复。关于StackOverflowErrorOutOfMemoryError的一个棘手问题是,一旦你找到一个,你绝对不能保证程序的状态;例如,您使用的密钥数据结构可能处于不一致状态。这通常会使恢复变得困难或不可能。

答案 3 :(得分:1)

参数和局部变量在堆栈上分配(对象存在于堆上的引用类型和引用该对象的变量)。堆栈通常位于地址空间的上端,当它用完时,它会朝向地址空间的底部(即朝向零)。

您的流程还有一个堆,它位于流程的底端。在分配内存时,此堆可以向地址空间的上端增长。正如您所看到的那样,堆有可能发生碰撞&#34;堆栈(有点像技术板!)。 [source]

因此,StackOIverflowError将取决于您的堆栈大小以及堆大小,这将取决于执行到执行,因为GC等很多因素。

此外,正如名称所说,它是错误而不是异常。它没有恢复。 JVM将关闭。