java在这种情况下发生stackoverflow异常的原因是什么?
import java.math.BigInteger;
import java.util.HashMap;
/**
*
* @author cypronmaya
*/
public class test {
static HashMap<Integer, BigInteger> cache = new HashMap<Integer, BigInteger>();
public static void main(String[] args) {
System.out.println(factorial(20000));
}
public static BigInteger factorial(int n) {
BigInteger ret;
if (n == 0) {
return BigInteger.ONE;
}
if (null != (ret = cache.get(n))) {
return ret;
}
ret = BigInteger.valueOf(n).multiply(factorial(n - 1));
cache.put(n, ret);
return ret;
}
}
Exception in thread "main" java.lang.StackOverflowError at java.util.HashMap.get(Unknown Source)
嗨, 为什么我得到这个程序的stackoverflow异常
我知道stackoverflow通常意味着你有一个无限循环, 但当我使用10000或其他一些较小的数字时,这个效果很好,当使用大数字时,wht突然变成无穷大
# 1 楼答案
原因是您的阶乘函数是递归的,而不是tail recursion
这意味着每次调用“factorial”函数时,该调用都被放入堆栈
我不知道Java编译器是否可以生成尾部递归调用,但如果可以,您可以简单地将函数重构为尾部调用方式。否则,只需避免递归(无论如何,在命令式语言中这是一个很好的实践)
# 2 楼答案
每次调用的递归函数都会在堆栈中创建一个新指针,因此使用大量的递归函数调用可以得到StackOverflow异常
提示:将递归函数替换为要解析的循环
# 3 楼答案
调用堆栈溢出时会发生
StackOverflowError
。当嵌套调用过多时会发生这种情况(因为每个调用都需要在堆栈上保留空间,而且大小有限)。我想在你的情况下,20000太多了您可以使用^{} 标志修改JVM的堆栈大小。但我建议你用另一种方法来计算阶乘
# 4 楼答案
非递归版本(与其说是编译版本,不如说是堆栈溢出)。会有更清晰的方法来写这篇文章
# 5 楼答案
可以使用
-Xss switch
调整Java默认堆栈大小运行时的大小