有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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突然变成无穷大


共 (5) 个答案

  1. # 1 楼答案

    原因是您的阶乘函数是递归的,而不是tail recursion

    这意味着每次调用“factorial”函数时,该调用都被放入堆栈

    我不知道Java编译器是否可以生成尾部递归调用,但如果可以,您可以简单地将函数重构为尾部调用方式。否则,只需避免递归(无论如何,在命令式语言中这是一个很好的实践)

  2. # 2 楼答案

    每次调用的递归函数都会在堆栈中创建一个新指针,因此使用大量的递归函数调用可以得到StackOverflow异常

    提示:将递归函数替换为要解析的循环

  3. # 3 楼答案

    调用堆栈溢出时会发生StackOverflowError。当嵌套调用过多时会发生这种情况(因为每个调用都需要在堆栈上保留空间,而且大小有限)。我想在你的情况下,20000太多了

    您可以使用^{}标志修改JVM的堆栈大小。但我建议你用另一种方法来计算阶乘

  4. # 4 楼答案

    非递归版本(与其说是编译版本,不如说是堆栈溢出)。会有更清晰的方法来写这篇文章

    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;
               }
            }
        }
    }
    
  5. # 5 楼答案

    可以使用-Xss switch调整Java默认堆栈大小运行时的大小

    eg: java -Xss2048k YourClass