如何增加Java堆栈大小? [英] How to increase the Java stack size?

查看:123
本文介绍了如何增加Java堆栈大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问了这个问题,以了解如何在JVM中增加运行时调用堆栈的大小。我已经得到了答案,并且我还得到了许多有用的答案和注释,这些答案和注释与Java如何处理需要大型运行时堆栈的情况有关。我已经用响应摘要扩展了我的问题。

I asked this question to get to know how to increase the runtime call stack size in the JVM. I've got an answer to this, and I've also got many useful answers and comments relevant to how Java handles the situation where a large runtime stack is needed. I've extended my question with the summary of the responses.

最初我想增加JVM堆栈大小,以便像没有 StackOverflowError的运行一样的程序

Originally I wanted to increase the JVM stack size so programs like runs without a 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一样:

The corresponding configuration setting is the java -Xss... command-line flag with a large enough value. For the program TT above, it works like this with OpenJDK's JVM:

$ javac TT.java
$ java -Xss4m TT

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

One of the answers has also pointed out that the -X... flags are implementation dependent. I was using

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 ... ,以避免浪费不需要它的线程的内存。

It is also possible to specify a large stack only for one thread (see in one of the answers how). This is recommended over java -Xss... to avoid wasting memory for threads that don't need it.

我很好奇上面的程序需要多大的堆栈,所以我运行它 n 增加:

I was curious how large a stack the program above exactly needs, so I've run it n increased:


  • -Xss4m足够事实(1<< 15)

  • -Xss5m can can足够事实(1<<< 17)

  • -Xss7m足够事实( 1<<< 18)

  • -Xss9m足够事实(1<< 19)

  • -Xss18m足够事实(1<< 20)

  • -Xss35m足够事实(1<<< 21)

  • -Xss68m足够事实(1<< 22)

  • -Xss129m对于事实是足够的(1<< 23)

  • -Xss258m足够事实(1<<<<< 24)

  • -Xss515m足够事实(1 << 25)

  • -Xss4m can be enough for fact(1 << 15)
  • -Xss5m can be enough for fact(1 << 17)
  • -Xss7m can be enough for fact(1 << 18)
  • -Xss9m can be enough for fact(1 << 19)
  • -Xss18m can be enough for fact(1 << 20)
  • -Xss35m can be enough for fact(1 << 21)
  • -Xss68m can be enough for fact(1 << 22)
  • -Xss129m can be enough for fact(1 << 23)
  • -Xss258m can be enough for fact(1 << 24)
  • -Xss515m can be enough for fact(1 << 25)

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

From the numbers above it seems that Java is using about 16 bytes per stack frame for the function above, which is reasonable.

上面的枚举包含足够而不是足够,因为堆栈要求不确定:使用相同的源文件和相同的多次运行它 - Xss ... 有时会成功,有时会产生 StackOverflowError 。例如。对于1<< 20, -Xss18m 在10次中有7次运行就足够了, -Xss19m 也不够,但是 -Xss20m 就足够了(100次中的所有100次跑步)。垃圾收集,JIT启动或其他原因会导致这种不确定行为吗?

The enumeration above contains can be enough instead of is enough, because the stack requirement is not deterministic: running it multiple times with the same source file and the same -Xss... sometimes succeeds and sometimes yields a StackOverflowError. E.g. for 1 << 20, -Xss18m was enough in 7 runs out of 10, and -Xss19m wasn't always enough either, but -Xss20m was enough (in all 100 runs out of 100). Does garbage collection, the JIT kicking in, or something else cause this nondeterministic behavior?

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

The stack trace printed at a StackOverflowError (and possibly at other exceptions as well) shows only the most recent 1024 elements of the runtime stack. An answer below demonstrates how to count the exact depth reached (which might be a lot larger than 1024).

许多回复的人都指出它很好,安全编码实践,以考虑相同算法的替代,较少堆栈的实现。通常,可以将一组递归函数转换为迭代函数(使用例如 Stack 对象,该对象在堆上而不是在运行时堆栈上填充) 。对于这个特殊的事实函数,转换它很容易。我的迭代版本看起来像:

Many people who responded has pointed out that it is a good and safe coding practice to consider alternative, less stack-hungry implementations of the same algorithm. In general, it is possible to convert to a set of recursive functions to iterative functions (using a e.g. Stack object, which gets populated on the heap instead of on the runtime stack). For this particular fact function, it is quite easy to convert it. My iterative version would look like:

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 会溢出。重构事实所以它将返回 BigInteger 而不是 long 也会产生大输入的精确结果。

FYI, as the iterative solution above shows it, the fact function cannot compute the exact factorial of numbers above 65 (actually, even above 20), because the Java built-in type long would overflow. Refactoring fact so it would return a BigInteger instead of long would yield exact results for large inputs as well.

推荐答案

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

Hmm... it works for me and with far less than 999MB of stack:

> java -Xss4m Test
0

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

(Windows JDK 7, build 17.0-b05 client VM, and Linux JDK 6 - same version information as you posted)

这篇关于如何增加Java堆栈大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆