web-dev-qa-db-ja.com

Javascriptのスタックとヒープ? (最大コールスタックサイズを超えました)

JavaScriptで数百MBのデータをシャベルで処理する必要があるWebページを作成しようとしています。さまざまなブラウザで、さまざまなデータ量で「最大呼び出しスタックサイズを超えました」というエラーが発生します。

コードを調べて、関数内のローカル変数をよりグローバルなスコープに移動し、スタックではなくヒープに割り当てられるようにすることで、この問題を修正できますか?または、これらの概念はJavaScriptに存在しませんか? (私が知る限り、データに主要な再帰ループがないため、エラーの原因となっているのは実際にはいくつかの巨大な文字列/数値配列です)

これが不可能な場合、ブラウザにメモリを予約するように依頼する方法はありますか?

29
Markus A.

Javascriptでは、メモリをスタック/ヒープに分離することはありません。表示されるのは、次のいずれかです。

  1. 深すぎる再帰。その場合、アルゴリズムを見直して反復性を高め、再帰を少なくして、ブラウザによって課せられる制限に達しないようにする必要がありますコールスタック
  2. アルゴリズムに深い再帰がない場合でも、コードが生成されていることを考えると、これは十分に深い呼び出しである可能性があります。
  3. 最後に、一部のエンジンは、高速ルックアップのために、ある種の内部スタックに関数の引数とスコープ付きの名前付き変数を割り当てる場合があります。あなた(または自動生成されたコード)が関数で文字通り何千ものローカル変数または引数を使用する場合、これはエンジン固有の制限もオーバーフローする可能性があります。
16
Oleg V. Volkov

OK、問題を理解しました。私のコードには実際には再帰はありませんでした。たとえば、私の犯罪者である <array>.splice(...) のような「可変引数」関数である場合、数百の引数を使用してJavaScript関数を呼び出すことは確かに可能です。

余談: [〜#〜] gwt [〜#〜] Java関数 System.arraycopy(...)を実装します JavaScriptスプライス関数を多かれ少なかれ巧妙な方法で使用します。

spliceは、ターゲット配列に挿入する任意の数の入力要素を受け入れます。次の構成を使用して、これらの入力要素を別の配列から渡すことができます。

var arguments = [index, howmany].concat(elements);
Arrays.prototype.splice.apply(targetarray, arguments);

これは、次を呼び出すことと同じです。

targetarray.splice(index, howmany, elements[0], elements[1], elements[2], ...);

elementsが大きくなった場合(さまざまなブラウザでの「big」の意味については以下を参照)、canその内容が関数呼び出しのためにスタックにロードされるため、「最大呼び出しスタックサイズを超えました」エラーなしの再帰が発生します。

この問題を示す短いスクリプトを次に示します。

var elements = new Array();
for (i=0; i<126000; i++) elements[i] = 1;
try {
    var arguments = [0, 0].concat(elements);
    Array.prototype.splice.apply(elements, arguments);
    alert("OK");
} catch (err) {
    alert(err.message);
}

このスクリプトを使用すると、「大きい」とは次のことを意味します。

  • Chrome 19:要素には約125,000の数字が含まれています
  • Safari 5.1(Windowsの場合):要素には約65,000の数値が含まれます
  • Firefox 12:要素には約500,000の数字が含まれています
  • Opera 11.61:要素には約1,000,000の数字が含まれています

そして勝者は次のとおりです。変更のためのInternetExplorer 8!この関数呼び出しが失敗する前に、すべてのシステムメモリを使い果たす可能性があります。

補足:FirefoxとOperaは実際には別の(より便利な)エラーメッセージをスローします:Function.prototype.apply:argArrayが大きすぎます

27
Markus A.