コールスタック・サイズの最大は? どこまで関数は深く呼び出せるのか? (JavaScript)


コールスタック・サイズの最大は?

どこまで関数は深く呼び出せるのか?

例えばこんなコード:

// 深く潜る
function diveDeep(n) {
    return diveDeep(n + 1);
}

再帰呼び出しをしているが、終了条件が無いので止まらない。

で、最大でどのくらいまで深く関数を呼べるのか試してみた。

TL;DR 結果は以下の通り

PCの環境の違いとか、ブラウザの実行状況などで、差が出てくるので、
何回か試してみて、一番大きかった数字を書いた。

順位 ブラウザ バージョン 最大コールスタック・サイズ
1 Node.js(v8) v6.9.2-x86 31,444
2 Chrome(v8) 54.0.2807.0 31,424
3 Firefox 50.0 15,538
4 Edge 14.14393 11,528
5 IE11 Trident/7.0 10,787
6 jjs(nashorn) 1.8_60 1,187
- Node.js(v8) v6.9.2-x86 31,444
- Node.js(v8) v6.9.2-x64 15,699
- Node.js(v8) v7.2.1-x86 31,412
- Node.js(v8) v7.2.1-x64 15,664
- Chrome Canary 57.0.2947.0 4,638

32bit版のv8がダントツ。Google, Mozilla, Microsoftの順って感じ。
64bit版のv8になると半減するね。まぁ、そういうもんか。
Canaryはカナリひどい。

※OS: Windows 10 (64bit), Memory: 16GB (2016/12/11時点)

HTMLのソース

いくつかのブラウザで試してみた。Chrome, Firefox, Edge, IE11 など。

max-call-stack-size.html
<!doctype html>
<meta charset="UTF-8">
<p>Maximum call stack size:</p>
<script src="max-call-stack-size.js"></script>

JavaScriptのソース

ブラウザ以外では、nodeとjjs (nashorn; Javaに付いているやつ) で試してみた。

max-call-stack-size.js
// 深く潜る
function diveDeep(n) {
    try {
        return diveDeep(n + 1);
    } catch (e) {
        return {count: n, error: e};
    }
}

// メイン
displayVersion(); // バージョンを表示
var result = diveDeep(0); // 深く潜る
// 結果を表示
pr('Maximum call stack size: ' + result.count);
pr('Error: ' + result.error);
var keys = (Object.getOwnPropertyNames || Object.keys)(result.error);
for (var i in keys)
    pr('Error.' + keys[i] + ': ' + result.error[keys[i]]);

// ブラウザのバージョン等を表示
function displayVersion() {
    pr(typeof navigator !== 'undefined' &&
            navigator.userAgent &&
            'Browser: ' + navigator.userAgent ||
        typeof process !== 'undefined' &&
            process.version &&
            'Node.js: ' + process.version ||
        'other');
}

// 表示
function pr(x) {
    if (typeof document !== 'undefined' && document.writeln)
        document.writeln((x + '\n\n').split('\n').join('<br/>\n'));
    /*else*/ if (typeof console !== 'undefined' && console.log)
        console.log(x);
    else if (typeof print !== 'undefined')
        print(x);
}

実行結果

Node(x86)

Node(x86)
Node.js: v6.9.2
Maximum call stack size: 31444
Error: RangeError: Maximum call stack size exceeded
Error.message: Maximum call stack size exceeded
Error.stack: RangeError: Maximum call stack size exceeded
    at diveDeep (xxx/max-call-stack-size.js:6:3)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)
    at diveDeep (xxx/max-call-stack-size.js:4:10)

Chrome

Chrome
Maximum call stack size:

Browser: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Maximum call stack size: 31424
Error: RangeError: Maximum call stack size exceeded
Error.stack: RangeError: Maximum call stack size exceeded
    at diveDeep (file:///max-call-stack-size.js:6:3)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
Error.message: Maximum call stack size exceeded

Firefox

Firefox
Maximum call stack size:

Browser: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0

Maximum call stack size: 15538

Error: InternalError: too much recursion

Error.fileName: file:///max-call-stack-size.js

Error.lineNumber: 3

Error.columnNumber: 1

Error.message: too much recursion

IE11

IE11
Maximum call stack size:
Browser: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.1; rv:11.0) like Gecko
Maximum call stack size: 10787
Error: Error: スタック領域が不足しています。
Error.message: スタック領域が不足しています。
Error.description: スタック領域が不足しています。
Error.number: -2146828260
Error.stack: Error: スタック領域が不足しています。
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)

Edge

Edge
Maximum call stack size:
Browser: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393
Maximum call stack size: 11528
Error: Error: Out of stack space
Error.message: Out of stack space
Error.description: Out of stack space
Error.number: -2146828260
Error.stack: Error: Out of stack space
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)
   at diveDeep (file:///max-call-stack-size.js:4:3)

jjs (nashorn; Java 8)

jjs
>jjs -v
nashorn 1.8.0_60

>jjs max-call-stack-size.js
other
Maximum call stack size: 1187
Error: java.lang.StackOverflowError
max-call-stack-size.js:16 TypeError: java.lang.StackOverflowError is not an Object

Chrome Canary

ChromeCanary
Maximum call stack size:

Browser: Mozilla/5.0 (Windows NT 10.0.14393; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2947.0 Safari/537.36
Maximum call stack size: 4638
Error: RangeError: Maximum call stack size exceeded
Error.stack: RangeError: Maximum call stack size exceeded
    at diveDeep (file:///max-call-stack-size.js:6:3)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
    at diveDeep (file:///max-call-stack-size.js:4:10)
Error.message: Maximum call stack size exceeded

でっていう

で、何の役にも立たない...

以下の記事を書いた時に気になったので調べただけです。
竹内関数を遅延評価で高速化してみた(JavaScript/Node.js/ES2015/ES6) - Qiita