在Eclipse中执行下面粘贴的代码时,我遇到以下异常大约有1次:
Exception in thread "main" java.lang.StackOverflowError
at src.Adder.recursiveSumAllNumbersUpTo(Driver.java:33)
at src.Adder.recursiveSumAllNumbersUpTo(Driver.java:37)
... *(there are 1024 lines in this stack)*
另外两次,它按预期吐出结果(每次运行之间的时间略有不同):
Recursive: 467946
Non Recursive: 61282
Difference between recursive and non-recursive: 406664
Sum from recursive add: 19534375
Sum from non-recursive add: 19534375
为什么异常只发生(看似)约30%的时间?
以下是代码:
public class Driver {
public static void main(String[] args) {
Adder adder = new Adder();
int valueToSumTo = 6250;
long startTime = System.nanoTime();
int raSum = adder.recursiveAddAllNumbersUpTo(valueToSumTo);
long endTime = System.nanoTime();
long raDif = endTime - startTime;
System.out.println("Recursive: " + (raDif));
startTime = System.nanoTime();
int nonRaSum = adder.nonRecursiveAddAllNumbersUpTo(valueToSumTo);
endTime = System.nanoTime();
long nonRaDif = endTime - startTime;
System.out.println("Non Recursive: " + (nonRaDif));
System.out.println("Difference between recursive and non-recursive: " + (raDif - nonRaDif));
System.out.println("Sum from recursive add: " + raSum);
System.out.println("Sum from non-recursive add: " + nonRaSum);
}
}
class Adder {
public int recursiveAddAllNumbersUpTo(int i) {
if (i == 1) {
return i;
}
return i + recursiveAddAllNumbersUpTo(i - 1);
}
public int nonRecursiveAddAllNumbersUpTo(int i) {
int count = 0;
for(int num = 1; num <= i; num++) {
count += num;
}
return count;
}
}
答案 0 :(得分:2)
每次递归方法调用自身时,一切都会进入堆栈,而像你这样的算法需要一个非常深的堆栈。
要解决您的问题,您应该增加堆栈大小。
您可以通过使用-Xss参数调用JVM来实现。
如果您正在使用Eclipse,则可以通过执行以下操作来执行此操作:
如果配置不够,请尝试更大的堆栈。
答案 1 :(得分:0)
试着看一下是否有用:
FROM(http://www.odi.ch/weblog/posting.php?posting=411)
Java堆栈大小神话
Java如何使用堆栈基本上 无证。所以我们开发人员只能找到自己。 今天我写了一些有趣的测试代码,令人惊讶 结果。对于我的测试,我在RedHat Enterprise下使用了Sun JDK 1.5.0_12 Linux 3.
首先,我想知道VM为线程选择的堆栈大小。 我发现ulimit -s参数对它没有直接的影响 VM选择的堆栈大小。默认值显然是512kb,并且可以 可以使用-Xss和-XX:ThreadStackSize参数自由更改。 但我找不到那些之间的行为差异 参数。他们似乎做了同样的事情。我发现了 这台Linux机器能够以大约的速度创建新线程 每秒5000次。
我通过创建新线程并设置它们来执行这些测试 在一次阻塞等待电话中立刻睡着了。我一直在创造线程 直到VM内存不足。使用512k堆栈的线程数 大约是3700,大约7300的256k堆栈,大约13700的128k。
这导致堆栈的以下内存消耗: 3700 x 512kB = 1850MB 7300 x 256kB = 1825MB 13700 x 128kB = 1713MB
当然,32位进程限制为4GB的地址空间(减1) 或者内核为2 GB)。所以记忆是很自然的 接近这些2GB减去堆大小。 (注意Stack永远不会 从堆中分配。)
接下来我测试了我可以调用递归方法的深度,直到我 得到堆栈溢出。我通过修改初始程序来做到这一点,所以 每个线程都会递归到一个方法,直到它到达堆栈 溢出,然后睡着了。该线程记录了最大递归 深度。这就是我得到了非常奇怪的结果。尤其是与 服务器VM最大深度在1750和1750之间变化很大 5700个电话(128k筹码)!这远不是常数,这本来就是 是我的第一个猜测。对于客户端VM,数量通常较低 但变化不大:1100到1650之间。
在测试开始时,最大深度似乎也较低 并且到最后增加。
答案 2 :(得分:0)
使用堆栈大小:-Xss32m
允许堆栈为32 Mo.
注意:AFAIK,java不处理(为什么?!)尾递归优化。