递归计算中偶尔出现StackOverflowError

时间:2013-09-19 14:39:20

标签: java eclipse

在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;
    }   
}

3 个答案:

答案 0 :(得分:2)

每次递归方法调用自身时,一切都会进入堆栈,而像你这样的算法需要一个非常深的堆栈。

要解决您的问题,您应该增加堆栈大小。

您可以通过使用-Xss参数调用JVM来实现。

如果您正在使用Eclipse,则可以通过执行以下操作来执行此操作:

  1. 右键单击您的项目 - &gt;以 - &gt;运行运行配置;
  2. 转到参数选项卡;在VM参数中,写下:“ - Xss4m”
  3. 如果配置不够,请尝试更大的堆栈。

答案 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堆栈,大约137​​00的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不处理(为什么?!)尾递归优化。