如何增加Java堆栈的大小?

如何增加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)

  • -xss 5米就足够了

    fact(1 << 17)

  • -Xss7m就够了

    fact(1 << 18)

  • -Xss9m就够了

    fact(1 << 19)

  • -Xss 18m就够了

    fact(1 << 20)

  • -Xss35m可以满足

    fact(1 << 21)

  • -Xss68m可以满足

    fact(1 << 22)

  • -Xss129m足以

    fact(1 << 23)

  • -Xss258m足以满足

    fact(1 << 24)

  • -Xss 515米就够了

    fact(1 << 25)

从上面的数字来看,Java似乎为上面的函数使用了大约16个字节的堆栈帧,这是合理的。

上面的枚举包含就够了而不是就够了,因为堆栈要求不是确定性的:使用相同的源文件和相同的源文件多次运行它。-Xss...有时成功,有时产生StackOverflowError..例如,1<20,-Xss18m10中的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));
  }}

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


慕虎7371278
浏览 2024回答 3
3回答

www说

嗯.。它适用于我,而且堆栈的容量远远小于999 MB:>&nbsp;java&nbsp;-Xss4m&nbsp;Test0(Windows JDK 7,构建17.0-B05客户端VM,Linux JDK 6-与您发布的版本信息相同)

qq_花开花谢_0

我假设您是通过堆栈跟踪中的重复行计算“1024的深度”吗?显然,Throwable中的堆栈跟踪数组长度似乎限制在1024。尝试以下程序:public&nbsp;class&nbsp;Test&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fact(1&nbsp;<<&nbsp;15)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;(StackOverflowError&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("true&nbsp;recursion&nbsp;level&nbsp;was&nbsp;"&nbsp;+&nbsp;level); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("reported&nbsp;recursion&nbsp;level&nbsp;was&nbsp;"&nbsp;+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.getStackTrace().length); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;int&nbsp;level&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;long&nbsp;fact(int&nbsp;n)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;level++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;n&nbsp;<&nbsp;2&nbsp;?&nbsp;n&nbsp;:&nbsp;n&nbsp;*&nbsp;fact(n&nbsp;-&nbsp;1); &nbsp;&nbsp;&nbsp;&nbsp;}}

开心每一天1111

如果您想使用线程堆栈大小,则需要查看HotSpot JVM上的-XSS选项。这在非HotSpot VM上可能有所不同,因为JVM的-X参数是特定于发行版的,IIRC。在热点上,这看起来就像java -Xss16M如果你想要16米的尺寸的话。类型java -X -help如果希望看到所有特定于发行版的JVM参数,则可以传入。我不确定这在其他JVM上是否同样工作,但它会打印所有HotSpot特定的参数。值得注意的是,我建议限制您在Java中使用递归方法。优化它们并不太好-比如JVM不支持尾递归(参见JVM是否阻止尾调用优化?)。尝试重构上面的阶乘代码,以使用while循环而不是递归方法调用。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java