我問過這個問題,以瞭解如何增加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