首页 文章

StackOverflowError何时发生? [重复]

提问于
浏览
7

这个问题在这里已有答案:

根据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

    深度取决于两件事:

    1:堆栈的大小 .

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

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

    Recovery

    有可能恢复 .

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

    但是,请注意以下有关错误的信息(来自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() 的调用将失败,因为堆栈上没有剩余空间用于返回地址 .

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

  • 3

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

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

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

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

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

    Read more about Errors here

    Read more about Java stack size myths here

    Edit:

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

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

  • 2

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

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

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

  • 6

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

    您的进程还有一个堆,它位于流程的底端 . 在分配内存时,此堆可以向地址空间的上端增长 . 正如你所看到的那样,堆栈有可能与堆栈(有点像技术板块!!!) . [source]

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

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

相关问题