How to avoid StackOverflowError for a recursive fu

2020-02-27 10:37发布

问题:

I'm writing a function that will call itself up to about 5000 times. Ofcourse, I get a StackOverflowError. Is there any way that I can rewrite this code in a fairly simple way?:

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

}

By the way, what is the limitation of how deep we may call the functions?

回答1:

Use an explicit stack of objects and a loop, rather than the call stack and recursion:

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


回答2:

default stack size in java is 512kb. if you exceed that program will terminate throwing StackOverflowException

you can increase the stack size by passing a JVM argument : -Xss1024k

now stack size is 1024kb. you may give higher value based on your environment

I don't think we can programmatically change this



回答3:

You can increase the stack size by using -Xss4m.



回答4:

You may put your "Block"s into a queue/stack and iterate as long as Blocks are available.



回答5:

It's obvious that you get StackOverflow with such branching factor of your recursion. In other languages it can be achieved by Tail Call Optimization. But I suppose your problem needs another way to solve.

Ideally, you perform some check on Block. Maybe you can obtain list of all blocks and check each of them iteratively?



回答6:

In most cases recursion is used in a wrong way. You shouldn't get a stack over flow exception. Your method has no return type/value. How do you ensure your initial Block b is valid?

If you are using recursion, answer yourself the following question:

  • what is my recursion anchor (when do i stop with recursion)
  • what is my recursion step (how do I reduce my number of calculations)

Example:

  • n! => n*n-1!

my recursion anchor is n == 2 (result is 2), so I can calculate all results beginnging from this anchor.

my recursion step is n-1 (so each step I get closer to the solution (and in this fact to my recursion anchor))