在return语句中调用方法会导致堆栈在Java中溢出吗?

时间:2015-09-25 08:19:41

标签: java

我听说当我调用一个方法时,局部变量会保存在内存的堆栈区域中,所以如果我使用这样的代码:

class aClass{
   public int val;
   public int dosth(int a){
      val++;
      int localVariable = val;
      if(val > 100){
         return 0;
      }
      return dosth(a);
   }
}

这将导致所有localVariables堆叠,直到它符合

return 0;

语句???

4 个答案:

答案 0 :(得分:1)

标准java JVM没有优化endrecursive调用,所以你将构建一个堆栈(可能会溢出),是的。是的。

答案 1 :(得分:0)

在我所知道的所有当前JVM实现中,以下内容将存储在堆栈中

  • 论据a
  • 本地变量localVariable

事实上,您可以尝试将上述方法更改为

  public int dosth(int a){
      return dosth(a);
  }

您很可能最终获得StackOverflowException。 存储在局部变量中的数据越多,异常就会越快发生。

在JVM上运行但针对tail-end-recursion进行优化的语言中,您将看不到StackOverflowException。事实上,JVM的未来版本可能会这样做。在这种情况下,上面的过程将变成一个while(true)循环,所以不要指望将来这是真的。

答案 2 :(得分:0)

对于每个方法调用,它将被推入具有所有局部变量的堆栈。但是你不应该过多担心局部变量。 (即使为每个堆栈分配大量内存也会加快StackOverflow的发生

你应该确保,当你实现一个递归方法时,可以达到终止条件,当没有任何点进行另一次递归调用时,方法应该返回到最快调用点。

如果您只是进行常规方法调用,那么您很可能会受到 StackOverflowException 的影响,因为要推送的堆栈数量的阈值相当高(不固定,但您可以拥有在溢出之前多达100,000个堆栈)。 (可以调整限制)。

你应该担心的是进行无限递归调用。这肯定会导致 StackOverFlowException

  

在return语句中调用方法会导致堆栈在Java中溢出吗?

你所拥有的是尾递归并且 没有这样的东西 因为“尾递归是坏的,它肯定会导致StackOverFlow问题“。尾递归在某些情况下很有用,只是有时你可以用一个可以增强某些性能的循环替换尾递归。

您可以运行代码,您将意识到它不会遇到StackOverFlowException。

答案 3 :(得分:0)

确实发生了什么。您已经对call stack进行了简洁的描述。

现在,这意味着每个函数调用都会增加堆栈。通常这不是问题,因为(尽管人们可能认为)调用永远不会深深嵌套。因此堆栈通常不会变得非常大。

一旦函数开始递归调用自身,它就会发生变化:突然,堆栈大小可能会迅速增长(取决于您的数据)。这就是为什么在使用递归来解决问题时需要注意的。

现在,您展示的代码是一个特例:递归调用是方法中发生的最后一件事。在那之后,我们所做的就是回归。这种特殊形式称为tail recursion。尾递归具有计算上等效于迭代的良好特性,原则上尾递归代码可以自动转换为迭代代码。这意味着我们可以编写优雅的代码,并且编译器会将它转换为不会溢出堆栈的代码,无论我们向它投入什么输入。

此功能在函数式编程语言中被大量使用,其中许多语言没有常规的“for”或“loop”指令,而是完全依赖递归。

(官方)Java编译器和Java运行时相比,do not optimise tail recursion and tail calls(到目前为止;这可能会在未来发生变化)。因此,您的代码最终会溢出堆栈。这种情况发生的速度取决于您的特定运行时环境(特别是,它取决于分配的堆栈大小;您可以通过java命令行选项-Xss来控制它)。虽然100次递归调用不足以溢出堆栈:通常至少需要几千个。