我问过这个问题,以了解如何增加JVM中的运行时调用堆栈大小。我已经得到了一个答案,并且我还得到了许多有用的答案和评论,这些答案和评论与Java如何处理需要大型运行时堆栈的情况相关。我已经回答了问题的总结。如何增加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可以连接足够ough为
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
会产生精确的结果大投入为好。
看起来比它更简单。 fact()被递归地调用32K次。这应该小于1MB的堆栈。 : -/ – 2010-09-13 12:51:08
@Aaron:+函数开销,这是..一个LOT – halfdan 2010-09-13 12:53:04
除了你的堆栈问题。请注意,你正在炸毁你的长整数。 1 << 4是我在使用负数之前可以使用的最大值,然后变为0.尝试使用BigInteger – Sean 2010-09-13 13:36:00