递归函数中的调用堆栈大小:最大调用堆栈大小低于预期

时间:2016-01-02 20:44:54

标签: javascript google-chrome recursion callstack

我在编写的递归算法中搜索问题。

此算法会在某些输入上抛出RangeError: Maximum call stack size exceeded(在Chrome中)错误。但我追踪的调用堆栈大小只有6k-9k左右。

This testfrom this SO answer)表示Chrome中的最大调用堆栈大小约为42k。

运行一些测试后,我发现,在递归函数上有参数似乎会降低可用的调用堆栈大小:

带参数:超过 ~31k 调用堆栈大小(Chrome,边缘约15k)

var recursionA = function(a, b) {
    count++;
  if (count < 100000) {
    recursionA(a, b);
  }
}

没有参数:超过 ~42k 的调用堆栈大小(Chrome,边缘约16.5k)

var recursionB = function() {
    count++;
  if (count < 100000) {
    recursionB();
  }
}

See fiddle here

  1. 当有参数调用函数时,任何人都可以解释为什么可用的调用堆栈大小明显更低。
  2. 由于我的递归函数需要2个参数:如何利用浏览器的最大调用堆栈大小?
  3. 是否有其他因素可能会减少可用的调用堆栈大小?

2 个答案:

答案 0 :(得分:1)

  1. 堆栈的大小是一些字节,而不是一些函数调用。您添加到函数调用的每个参数都会占用一些内存,因此可用的堆栈更少;
  2. 见上文
  3. 函数中的变量名为

答案 1 :(得分:1)

我只是创建另一个递归函数来调用递归函数并分割持续时间,这样你就不会最大化堆栈。下面是一个“callStackOptimizer”的例子,我刚刚写了一个关于复杂而昂贵的fizzbuzz游戏的编写方式,用更多功能的不可变风格编写,向您展示我的意思。

"use strict";

const isDivisibleBy = divisor => number => number % divisor === 0;

const isDivisibleBy3 = isDivisibleBy(3);
const isDivisibleBy5 = isDivisibleBy(5);
const isDivisibleBy3And5 = number => isDivisibleBy5(number) && isDivisibleBy3(number);

const rules = (bool1, bool2, bool3) => (value1, value2, value3) => number => {
    switch (true){
        case bool1(number):
            return value1;
        break;
        case bool2(number):
            return value2;
        break;
        case bool3(number):
            return value3;
        break;
        default:
            return number;
    }
};

const gameConditions = rules(
    isDivisibleBy3And5,
    isDivisibleBy3,
    isDivisibleBy5
);

const fizzBuzzResults = gameConditions(
    "FizzBuzz",
    "Fizz",
    "Buzz"
);

const game = duration => value => (action, array = []) => {
    if (duration > 0){
        const nextValue = action(value);
        return game(duration - 1)(value + 1)(action, array.concat(nextValue))
    }
    else {
        return array
    }
};

const callStackOptimizer = (duration, times = Math.ceil(duration/10000), result = []) => rules =>{
    if (times > 0){
        const value = duration/times;
        const round = game(value)(value * times - value + 1)(rules);
        return callStackOptimizer(duration - value , times - 1, result.concat(round))(rules)
    }
    else {
        return result;
    }
};

const playFizzBuzz = duration => callStackOptimizer(duration)(fizzBuzzResults);

console.log(playFizzBuzz(100000));