如何避免递归函数的StackOverflowError

时间:2012-04-09 12:52:09

标签: java stack-overflow

我正在编写一个可以自我调用约5000次的函数。当然,我得到一个StackOverflowError。有什么方法可以用相当简单的方式重写这段代码吗?:

void checkBlocks(Block b, int amm) {

    //Stuff that might issue a return call

    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition) 
        checkBlocks(blockDown, amm);


    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
        checkBlocks(blockUp, amm);

    //Same code 4 more times for each side

}

顺便说一句,我们可以称之为功能的深度有多大限制?

6 个答案:

答案 0 :(得分:19)

使用显式堆栈对象和循环,而不是调用堆栈和递归:

void checkBlocks(Block b, int amm) {
  Stack<Block> blocks = new Stack<Block>();
  blocks.push(b);
  while (!blocks.isEmpty()) {
    b = blocks.pop();
    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition)
      blocks.push(block);
    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
      blocks.push(block);
  }
}

答案 1 :(得分:6)

java中的默认堆栈大小为512kb。如果超过该程序将终止抛出StackOverflowException

您可以通过传递JVM参数来增加堆栈大小: -Xss1024k

现在堆栈大小为1024kb。您可以根据您的环境提供更高的价值

我认为我们不能以编程方式更改此

答案 2 :(得分:0)

您可以使用-Xss4m增加堆栈大小。

答案 3 :(得分:0)

只要块可用,您就可以将“块”放入队列/堆栈中并进行迭代。

答案 4 :(得分:0)

很明显,你的StackOverflow具有递归的分支因子。在其他语言中,可以实现by Tail Call Optimization。但我想你的问题需要另一种方法来解决。

理想情况下,您会对Block执行一些检查。也许你可以获得所有块的列表并迭代地检查每个块?

答案 5 :(得分:0)

在大多数情况下,递归以错误的方式使用。您不应该获得堆栈溢出异常。 您的方法没有返回类型/值。 你如何确保你的初始Block b有效?

如果您正在使用递归,请回答以下问题:

  • 什么是我的递归锚点(我什么时候停止递归)
  • 我的递归步骤是什么(如何减少计算次数)

示例:

  • N! =&GT; N * N-1 <!/ LI>

我的递归锚点是n == 2(结果是2),所以我可以计算从这个锚点开始的所有结果。

我的递归步骤是n-1(所以每一步我都接近解决方案(在这个事实中我的递归锚))