我听说当我调用一个方法时,局部变量会保存在内存的堆栈区域中,所以如果我使用这样的代码:
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;
语句???
答案 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次递归调用不足以溢出堆栈:通常至少需要几千个。