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;
}
}
线程“main”中的异常java.lang.StackOverflowError at java.util.HashMap.get(未知来源)
您好, 为什么我得到这个程序的stackoverflow异常?
我知道stackoverflow通常意味着你有一个无限循环, 但是当我使用10000或其他一些较小的数字时,这种方法可以正常工作,但是大数字突然变得无穷无尽?
答案 0 :(得分:5)
调用堆栈溢出时发生StackOverflowError
。当你有太多嵌套调用时会发生这种情况(因为每个调用都需要在堆栈上保留空间,并且它是有限大小的)。我想在你的情况下,20000太多了。
您可以使用-Xss
标志修改JVM的堆栈大小。但我建议您找到一种不同的方法来计算阶乘。
答案 1 :(得分:2)
每次调用时递归函数都会在堆栈中创建一个新指针,因此对于递归函数的大量调用,您可以获得StackOverflow异常......
提示:用循环替换递归函数来解析。
答案 2 :(得分:1)
原因是你的阶乘函数是递归的,而且不是tail recursion。
这意味着每次调用“factorial”函数时,此调用都会被置于堆栈中。
我不知道Java编译器是否可以生成尾递归调用,但如果可以的话,您可以简单地将函数重构为尾调用方式。否则只是避免递归(无论如何都是命令式语言中的一种好习惯)。
答案 3 :(得分:0)
非递归版本(不像编译那么多 - 这是Stack Overflow)。将有更清晰的方式来写这个。
public class Test {
private static final Object lock = new Object();
private static final List<BigInteger> cache = new ArrayList<>(
Arrays.asList(BigInteger.ONE)
);
public static void main(String[] args) {
System.out.println(factorial(20000));
}
public static BigInteger factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
int r = cache.size();
if (n < r) {
return cache.get(n);
}
BigInteger current = cache.get(r-1);
for (;;) {
current = BigInteger.valueOf(r).multiply(current);
cache.add(current);
if (n == r) {
return current;
}
++r;
}
}
}
}
答案 4 :(得分:0)
您可以使用-Xss switch
eg: java -Xss2048k YourClass