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

Call Stack size in recursive functions: Maximum call stack size is lower than expected

我正在寻找我编写的递归算法中的问题。

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

This test (from this SO answer)表示在Chrome.

中最大调用栈大小约为42k

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

带参数: ~31k 上超出了调用堆栈大小(Chrome,Edge 上~15k)

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

没有参数: ~42k 上的调用堆栈大小超出(Chrome,Edge 上的~16.5k)

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

See fiddle here

  1. 谁能解释一下,为什么在使用参数调用函数时可用的调用堆栈大小明显变小。
  2. 由于我的递归函数需要 2 个参数:我如何利用浏览器的最大调用堆栈大小?
  3. 还有其他因素可能会减少可用调用堆栈的大小吗?
  1. 堆栈的大小是字节,而不是函数调用。您添加到函数调用中的每个参数都会消耗一些内存,因此可用堆栈更少;
  2. 见上1
  3. 调用函数中的变量

我只想创建另一个递归函数来调用该递归函数并拆分持续时间,这样您就不会最大化堆栈。这是一个 "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));