29

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

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

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

4

2 に答える 2

29

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

余談ですが、 GWTSystem.arraycopy(...)は、多かれ少なかれ巧妙な方法で JavaScript スプライス関数を使用して Java 関数を実装しています。

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

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

これは、次の呼び出しと同等です。

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

要素が大きくなると(さまざまなブラウザでの「大きい」の意味については以下を参照してください)、その内容が関数呼び出しのスタックに読み込まれるため、再帰なしで「最大呼び出しスタック サイズを超えました」というエラーが発生する可能性があります。

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

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 の数字が含まれます

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

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

于 2012-06-26T16:19:39.257 に答える
16

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

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