最大コールスタックサイズ超過エラー


533

Direct Web Remoting(DWR)JavaScriptライブラリファイルを使用していて、Safari(デスクトップおよびiPad)でのみエラーが発生する

それは言う

呼び出しスタックの最大サイズを超えました。

このエラーは正確には何を意味し、処理を完全に停止しますか?

また、Safariブラウザの修正(実際にはiPad Safari

JS:実行がタイムアウトを超えました

私が想定しているのは同じコールスタックの問題です)


2
変数を(宣言せずに)送信しようとするとdata、ajaxでこのエラーが発生しました。変数を宣言してエラーを修正しました。
phpfresher

回答:


621

これは、コードのどこかで、呼び出しスタックの制限に達するまで、別の関数を呼び出す関数などを呼び出していることを意味します。

これはほとんどの場合、基本ケースが満たされていない再帰関数が原因です。

スタックを表示する

このコードを検討してください...

(function a() {
    a();
})();

これは、いくつかの呼び出しの後のスタックです...

Webインスペクター

ご覧のとおり、呼び出しスタックは、ブラウザのハードコーディングされたスタックサイズまたはメモリの枯渇という制限に達するまで増加します。

それを修正するには、再帰関数が満たすことができる基本ケースを持っていることを確認してください...

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);

6
Thxたくさんそれのために..スタック制限が使い果たされていることを私ができる方法/ツールはあります..これも、巨大なライブラリファイルであり、私が作成したものではないため、どこにあるのか完全にはわかりません問題が発生している可能性があります..
testndtv

52
@Oliver 300兆回近く関数を実行する必要がある場合、おそらく何かがおかしいでしょう。
ceejayoz 14

3
@オリバー-あなたは動的プログラミングを調べたいかもしれません-私の推測ではあなたはそれほど多くのユニークな解決策を持っていません、あなたはステップを繰り返しているので、二次式ではなく多項式時間になるようにプログラムする必要があるかもしれません。en.wikipedia.org/wiki/Dynamic_programming
newshorts

4
@Akhoy通常の関数ではありますが、再帰的な関数について考えてください。それは別のもの(それ自体)を呼び出し、前者の戻りアドレスをスタックに残します(そうでなければ、PCはどこに行くべきかを知っていますか?)これはもちろん、スタックに戻りアドレスをプッシュするたびに、再び自分自身を呼び出します。これが次の世紀に満たされる可能性が低い基本ケースのために逃げると、スタックオーバーフローが発生します。
アレックス

5
コードは、同じ非効率的なセグメントを134217728回実行します。その遅い冗談はありません。ビットレベルの演算子を使用して、9レベルのループを1レベルのループに展開できるようにする必要があります。
ジャックギフィン2017年

82

同じJavaScriptファイルを誤って2回インポート/埋め込んだ場合に、インスペクタの[リソース]タブで確認することで、これが発生することがあります。


9
この問題は通常、誤って同じJSファイルを2回インポート/埋め込んだ場合に発生します。再帰ループを引き起こす正確なプロセスは、私が推測したいものではありませんが、同じ料金ゲートウェイを介して2つの同じ車を時速100マイルで運転するようなものだと思います。
lucygenik 14年

3
これは事実ではないと思います。2つの同じ種類の関数または変数が埋め込まれている場合、後者は前の定義をオーバーライドします。
ssudaraka

ええ...なぜそれが起こるのか、プロセスが何なのか本当に分かりません。
lucygenik 2017年

パーティーには少し遅れますが、コードが関数の外にあるとき、両方が2つのJSファイル内で実行され、おそらく関数の外にあるので、一方が互いに上書きしないと想像します。
キリアンコリンズ

1
@lucygenik次回投稿でトロールの編集を承認する際により注意したい場合。この投稿は、ほとんどのスパム(チェック履歴)として削除された
ジャン=フランソワ・ファーブル

57

私の場合、値の代わりに入力要素を送信していました:

$.post( '',{ registerName: $('#registerName') } )

の代わりに:

$.post( '',{ registerName: $('#registerName').val() } )

これにより、Chromeタブがフリーズし、ページが応答しなくなったときの「待機/終了」ダイアログが表示されなくなりました...


3
なぜこのようなエラーの例外はないのでしょうか。
Džuris

おかげでたくさんの、これは私を救った
EME波動

これを可能な解決策として追加しようとしていました。私はまさにこれをやったlol
Michael Buchok

31

コードのどこかに再帰ループがあります(つまり、スタックがいっぱいになるまで、最終的に何度も自分自身を呼び出す関数)。

他のブラウザでは、スタックが大きい(代わりにタイムアウトが発生する)か、何らかの理由でエラーが発生します(配置が不適切なtry-catchなど)。

エラーが発生したときにデバッガーを使用してコールスタックを確認します。


返信ありがとうございます。IE / FFでは、コードは正常に実行されるようです。デスクトップSafariおよびiPad Safariでのみ、エラーが発生します。実際、JSファイルは私が作成したものではなく、ライブラリファイル(DWR engine.jsから)です。directwebremoting.org また、「デバッガでコールスタックを確認する」と言ったとき、Safariインスペクタを使用してそれを行うにはどうすればよいですか。
testndtv 2011年

Safari Inspectorの経験はありません。JavaScriptデバッガーを開いて、ページをロードしてみてください。キャッチされていないエラーがスローされると、デバッガーが停止します。
それでもうまく

同じ名前の2つの関数がありました!! DOH!
jharris8567 14年

16

スタックオーバーフローを検出する際の問題は、スタックトレースがほどけ、実際に何が起こっているかを確認できない場合があることです。

これに役立つChromeの新しいデバッグツールがいくつか見つかりました。

ヒットPerformance tab、確認してJavascript samples有効になっていると、あなたはこのような何かを得るでしょう。

オーバーフローがどこにあるかは明らかです!クリックするextendObjectと、実際のコードで正確な行番号を確認できます。

ここに画像の説明を入力してください

また、役立つかそうでないかもしれないタイミングや赤いニシンを見ることができます。

ここに画像の説明を入力してください


実際に問題が見つからない場合のもう1つの便利なトリックは、問題がconsole.logあると思う場所にたくさんのステートメントを置くことです。上記の前のステップはこれを助けることができます。

Chromeでは、同じデータを繰り返し出力すると、次のように表示され、問題がより明確に示されます。この例では、スタックは最終的にクラッシュする前に7152フレームをヒットしました。

ここに画像の説明を入力してください


13

私の場合、次のようにして大きなバイト配列を文字列に変換していました。

String.fromCharCode.apply(null, new Uint16Array(bytes))

bytes 数百万のエントリが含まれていますが、スタックに収まりません。


私も同じラインで同じ問題を抱えていました!! thanx
ksh

大きなバイト配列を変換するための最良の解決策は何ですか?
ksh 2017

6
@KarthikHande 1回の呼び出しではなく、forループで行う必要があります。var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
ネイトグレン2017

JSON.parseを試してみましたが、うまくいきませんでした... Uintl8Arrayを使用しています
ksh

@KarthikHande問題全体を見ないと私にはわからない。詳細をすべて記入した別の質問を開いてください。
ネイトグレン2017

6

私の場合、クリックイベントは子要素に伝播していました。だから、私は以下を入れなければなりませんでした:

e.stopPropagation()

クリックイベント:

 $(document).on("click", ".remove-discount-button", function (e) {
           e.stopPropagation();
           //some code
        });
 $(document).on("click", ".current-code", function () {
     $('.remove-discount-button').trigger("click");
 });

これがhtmlコードです:

 <div class="current-code">                                      
      <input type="submit" name="removediscountcouponcode" value="
title="Remove" class="remove-discount-button">
   </div>

5

Chrome開発ツールバーコンソールでエラーの詳細を確認してください。これにより、コールスタック内の関数が提供され、エラーの原因となっている再帰に向けて案内されます。



3

ここでのほぼすべての回答は、これは無限ループによってのみ引き起こされる可能性があると述べています。それは真実ではありません。そうでなければ、深くネストされた呼び出しによってスタックをオーバーランする可能性があります(それが効率的であるとは言えませんが、それは確かに可能性の領域にあります)。JavaScript VMを制御できる場合は、スタックサイズを調整できます。例えば:

node --stack-size=2000

参照:Node.jsの最大コールスタックサイズを増やす方法


2

私の場合、2つのjQueryモーダルが重なり合って表示されていました。それを防ぐことで私の問題は解決しました。


2

最近取り組んでいる管理サイトにフィールドを追加しました-contact_type ...簡単ですよね?さて、select "type"を呼び出してjquery ajax呼び出しで送信しようとすると、jquery.jsの奥深くに埋め込まれたこのエラーで失敗します。これを行わないでください:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, type:type }
});

問題はそのtype:typeです-引数に「type」という名前を付けていると思います-typeという名前の値変数を持つことは問題ではありません。これを次のように変更しました。

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, contact_type:type }
});

そして、それに応じてsome_function.phpを書き直しました-問題は解決しました。


1

自分自身を呼び出す関数があるかどうかを確認します。例えば

export default class DateUtils {
  static now = (): Date => {
    return DateUtils.now()
  }
}

1

これもMaximum call stack size exceededエラーを引き起こす可能性があります:

var items = [];
[].push.apply(items, new Array(1000000)); //Bad

こっちも一緒:

items.push(...new Array(1000000)); //Bad

Mozilla Docsから:

ただし、注意してください。applythis wayを使用すると、JavaScriptエンジンの引数の長さ制限を超えるリスクがあります。引数が多すぎる(数万を超えると考える)関数を適用した場合の結果は、エンジンによって異なります(JavaScriptCoreには65536の引数のハードコードがあります)。動作)は指定されていません。一部のエンジンは例外をスローします。さらに悪質なことに、適用された関数に実際に渡される引数の数を制限する人もいます。この後者のケースを説明すると、そのようなエンジンに4つの引数の制限がある場合(実際の制限はもちろん大幅に高くなります)、上記の例に適用するために引数5、6、2、3が渡されたかのようになります。完全な配列ではなく。

だから試してください:

var items = [];
var newItems = new Array(1000000);
for(var i = 0; i < newItems.length; i++){
  items.push(newItems[i]);
}

0

コンピューターのChrome 32で作業が1つ減った場合、以下の同じコードの両方の呼び出し(例:17905対17904)。そのまま実行すると、「RangeError:最大呼び出しスタックサイズを超えました」というエラーが発生します。この制限はハードコードされていないようですが、マシンのハードウェアに依存しています。関数として呼び出された場合、この自発的な制限はメソッドとして呼び出された場合よりも高くなります。つまり、この特定のコードは、関数として呼び出されたときに使用するメモリが少なくなります。

メソッドとして呼び出されます:

var ninja = {
    chirp: function(n) {
        return n > 1 ? ninja.chirp(n-1) + "-chirp" : "chirp";
    }
};

ninja.chirp(17905);

関数として呼び出されます:

function chirp(n) {
    return n > 1 ? chirp( n - 1 ) + "-chirp" : "chirp";
}

chirp(20889);

0

再帰関数はクロームブラウザーで検索できます。Ctrl+ Shift + Jを押してから[ソース]タブを押すと、コードコンパイルフローが提供され、コード内のブレークポイントを使用して検索できます。


ただし、エラーの発生場所を特定するのが難しい場合もあります。私たちのサイトにはたくさんのJavaScriptがあります。
Mathias Lykkegaard Lorenzen、2015

0

私もここで同様の問題に直面しましたドロップダウンロゴアップロードボックスを使用してロゴをアップロードするときの詳細です

<div>
      <div class="uploader greyLogoBox" id="uploader" flex="64" onclick="$('#filePhoto').click()">
        <img id="imageBox" src="{{ $ctrl.companyLogoUrl }}" alt=""/>
        <input type="file" name="userprofile_picture"  id="filePhoto" ngf-select="$ctrl.createUploadLogoRequest()"/>
        <md-icon ng-if="!$ctrl.isLogoPresent" class="upload-icon" md-font-set="material-icons">cloud_upload</md-icon>
        <div ng-if="!$ctrl.isLogoPresent" class="text">Drag and drop a file here, or click to upload</div>
      </div>
      <script type="text/javascript">
          var imageLoader = document.getElementById('filePhoto');
          imageLoader.addEventListener('change', handleImage, false);

          function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {

                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }
      </script>
      </div>

CSS.css

.uploader {
  position:relative;
  overflow:hidden;
  height:100px;
  max-width: 75%;
  margin: auto;
  text-align: center;

  img{
    max-width: 464px;
    max-height: 100px;
    z-index:1;
    border:none;
  }

  .drag-drop-zone {
    background: rgba(0, 0, 0, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.12);
    padding: 32px;
  }
}

.uploader img{
  max-width: 464px;
  max-height: 100px;
  z-index:1;
  border:none;
}



.greyLogoBox {
  width: 100%;
  background: #EBEBEB;
  border: 1px solid #D7D7D7;
  text-align: center;
  height: 100px;
  padding-top: 22px;
  box-sizing: border-box;
}


#filePhoto{
  position:absolute;
  width:464px;
  height:100px;
  left:0;
  top:0;
  z-index:2;
  opacity:0;
  cursor:pointer;
}

修正前の私のコードは:

function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {
                  onclick="$('#filePhoto').click()"
                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }

コンソールのエラー:

ここに画像の説明を入力してください

onclick="$('#filePhoto').click()"divタグから削除することで解決しました。


どこでclick()を追加しましたか
Tsea

0

同じ問題に直面していましたが、ajaxで2回使用されたフィールド名を削除することで解決しました。

    jQuery.ajax({
    url : '/search-result',
    data : {
      searchField : searchField,
      searchFieldValue : searchField,
      nid    :  nid,
      indexName : indexName,
      indexType : indexType
    },
.....

0

私はこのスレッドが古いことを知っていますが、他の人を助けるためにこの問題を見つけたシナリオについて言及する価値があると思います。

次のようなネストされた要素があるとします。

<a href="#" id="profile-avatar-picker">
    <span class="fa fa-camera fa-2x"></span>
    <input id="avatar-file" name="avatar-file" type="file" style="display: none;" />
</a>

子要素のイベントはそれ自体に伝播し、例外がスローされるまで再帰的な呼び出しを行うため、親のイベント内で子要素のイベントを操作することはできません。

したがって、このコードは失敗します。

$('#profile-avatar-picker').on('click', (e) => {
    e.preventDefault();

    $('#profilePictureFile').trigger("click");
});

これを回避するには、2つのオプションがあります。


0

同じ名前の2つのJS関数があるため、このエラーが発生しました


0

Googleマップを使用している場合は、緯度経度が渡されnew google.maps.LatLngているかどうかが適切な形式かどうかを確認してください。私の場合、それらは未定義として渡されていました。


0

私の場合の問題は、親と同じパスを持つ子ルートがあるためです:

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: '', redirectTo: 'home', pathMatch: 'prefix' },
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

だから私は子供のルートの行を削除する必要がありました

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

0

私の場合、ajax呼び出しでこのエラーが発生し、その変数を渡そうとしたデータが定義されていないため、このエラーが表示されますが、定義されていない変数については説明されていません。私は、変数nが値を得たことを定義しました。


私も同様の方法で火傷しました。私の場合は、変数名を入力したためです...事実上同じことです。
user2366842

0

同じ問題に遭遇しましたが、何が悪いのか理解できず、バベルのせいになり始めました;)

ブラウザーでコードが例外を返さない:

if (typeof document.body.onpointerdown !== ('undefined' || null)) {

問題はひどく作成されました|| (または)babelが独自の型チェックを作成するときのパーツ:

function _typeof(obj){if(typeof Symbol==="function"&&_typeof(Symbol.iterator)==="symbol")

だから削除

|| null

バベルの蒸散がうまくいった。


0

私の場合、誤って同じ変数名を割り当てており、val関数に「class_routine_id」を割り当てています

var class_routine_id = $("#class_routine_id").val(class_routine_id);

それは次のようになるはずです:

 var class_routine_id = $("#class_routine_id").val(); 


0

React-Native 0.61.5を(npm 6.9.0&node 10.16.1)とともに使用しています

Projectに新しいライブラリをインストールしている間、

(例:npm install @ react-navigation / native --save)

最大コールスタックサイズ超過エラー

そのため、私は試します

sudo npm cache clean --force

(注:-以下のコマンドは通常 、npmキャッシュサイズに応じて1〜2分かかります)


-1

データ型の変換が原因で発生することもありました。たとえば、文字列と見なしたオブジェクトがある場合などです。

nodejsのsocket.idは、例としてjsクライアントでも、文字列でもありません。文字列として使用するには、前に文字列という単語を追加する必要があります。

String(socket.id);

-1

変数が宣言されていないときに、変数に値を割り当てようとしました。

変数を宣言するとエラーが修正されました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.