如何增加Java堆栈大小?

我问了这个问题,以了解如何增加JVM中的运行时调用堆栈大小。 我已经得到了一个答案,并且我还得到了许多有用的答案和评论,这些答案和评论与Java如何处理需要大型运行时堆栈的情况相关。 我已经回答了问题的总结。

最初我想增加JVM堆栈大小,以便程序运行时不会出现StackOverflowError

public class TT {
  public static long fact(int n) {
    return n < 2 ? 1 : n * fact(n - 1);
  }
  public static void main(String[] args) {
    System.out.println(fact(1 << 15));
  }
}

相应的配置设置是具有足够大的值的java -Xss...命令行标志。 对于上面的程序TT ,它可以像OpenJDK的JVM一样工作:

$ javac TT.java
$ java -Xss4m TT

其中一个答案也指出-X...标志是依赖于实现的。 我正在使用

java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1~8.04.3)
OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)

也可以为一个线程指定一个大堆栈(请参阅其中一个答案)。 建议使用java -Xss...来避免为不需要它的线程浪费内存。

我很好奇,究竟上面的程序堆栈多么大的需求,所以我已经运行n增加:

  • -Xss4m可以满足fact(1 << 15)
  • -Xss5m可以满足fact(1 << 17)
  • -Xss7m可以满足fact(1 << 18)
  • -Xss9m可以满足fact(1 << 19)
  • -Xss18m可以满足fact(1 << 20)
  • -Xss35m可以满足fact(1 << 21)
  • -Xss68m可以满足fact(1 << 22)
  • -Xss129m可以满足fact(1 << 23)
  • -Xss258m可以满足fact(1 << 24)
  • -Xss515m可以满足fact(1 << 25)
  • 从上面的数字看来,Java似乎对于上面的函数每个堆栈帧使用大约16个字节,这是合理的。

    上面的枚举可以是足够的,而不是足够的,因为堆栈需求是不确定的:使用相同的源文件多次运行它,并且相同的-Xss...有时成功,有时会产生StackOverflowError 。 例如,对于1 << 20, -Xss18m在10次中有7次足够了,并且-Xss19m也不总是足够的,但-Xss20m就足够了(100次中全部100次)。 垃圾收集,JIT踢,或其他事情导致这种非确定性行为?

    StackOverflowError (以及其他例外情况)上打印的堆栈跟踪仅显示运行时堆栈的最新的1024个元素。 下面的答案演示了如何计算到达的确切深度(可能比1024大很多)。

    许多回应者指出,考虑相同算法的替代性,较少堆栈实现是一种很好且安全的编码实践。 通常,可以将一组递归函数转换为迭代函数(使用例如Stack对象,而不是在运行时栈上填充)。 对于这个特殊的fact功能,它很容易转换。 我的迭代版本如下所示:

    public class TTIterative {
      public static long fact(int n) {
        if (n < 2) return 1;
        if (n > 65) return 0;  // Enough powers of 2 in the product to make it (long)0.
        long f = 2;
        for (int i = 3; i <= n; ++i) {
          f *= i;
        }
        return f;
      }
      public static void main(String[] args) {
        System.out.println(fact(1 << 15));
      }
    }
    

    仅供参考,如上面的迭代解决方案所示, fact函数无法计算65以上的实数(实际上,甚至超过20),因为Java内置类型long会溢出。 重构fact所以它会返回一个BigInteger而不是long这对于大量输入也会产生确切的结果。


    嗯...它适用于我,远远小于999MB的堆栈:

    > java -Xss4m Test
    0
    

    (Windows JDK 7,构建17.0-b05客户端VM和Linux JDK 6 - 与您发布的版本相同)


    我假设你通过堆栈跟踪中的循环线来计算“1024的深度”?

    显然,Throwable中的堆栈跟踪数组长度似乎限制为1024.请尝试以下程序:

    public class Test {
    
        public static void main(String[] args) {
    
            try {
                System.out.println(fact(1 << 15));
            }
            catch (StackOverflowError e) {
                System.err.println("true recursion level was " + level);
                System.err.println("reported recursion level was " +
                                   e.getStackTrace().length);
            }
        }
    
        private static int level = 0;
        public static long fact(int n) {
            level++;
            return n < 2 ? n : n * fact(n - 1);
        }
    }
    

    如果您想玩线程堆栈大小,您需要查看Hotspot JVM上的-Xss选项。 由于到JVM的-X参数是特定于分布的,IIRC,所以在非热点虚拟机上可能会有所不同。

    在Hotspot上,如果你想把大小设置为16兆,这看起来像java -Xss16M

    如果要查看可以传入的所有特定于分发的JVM参数,请键入java -X -help 。我不确定这是否与其他JVM相同,但它会打印所有热点特定参数。

    对于它的价值 - 我建议限制你在Java中使用递归方法。 在优化它们方面并不是太好 - 因为JVM不支持尾递归(请参阅JVM是否阻止尾调用优化?)。 尝试重构上面的因子代码以使用while循环而不是递归方法调用。

    链接地址: http://www.djcxy.com/p/80295.html

    上一篇: How to increase the Java stack size?

    下一篇: Process on linux ignoring resource limits