stackoverflow异常的原因是什么?

时间:2012-02-05 12:00:17

标签: java map stack-overflow

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或其他一些较小的数字时,这种方法可以正常工作,但是大数字突然变得无穷无尽?

5 个答案:

答案 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

调整Java默认堆栈大小运行时的大小
eg: java -Xss2048k YourClass