最大调用堆栈大小超出错误

tes*_*dtv 475 html javascript callstack webkit dwr

我正在使用Direct Web Remoting(DWR)JavaScript库文件,我只在Safari(桌面和iPad)中收到错误

它说

超出最大调用堆栈大小.

这个错误究竟是什么意思,它是否完全停止处理?

Safari浏览器的任何修复(实际上iPad Safari,它说

JS:执行超过了超时

我假设是相同的调用堆栈问题)

ale*_*lex 561

这意味着在代码中的某个地方,您正在调用一个函数,该函数又调用另一个函数,依此类推,直到达到调用堆栈限制.

这几乎总是因为具有未满足的基本情况的递归函数.

查看堆栈

考虑这段代码......

(function a() {
    a();
})();
Run Code Online (Sandbox Code Playgroud)

这是一些电话后的堆栈......

网络检查员

正如您所看到的,调用堆栈会一直增长,直到达到限制:浏览器硬编码堆栈大小或内存耗尽.

为了解决这个问题,请确保您的递归函数具有能够满足的基本情况......

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

  • @Oliver如果你必须运行近300万亿次的函数,**你可能做错了什么.** (45认同)
  • Thx很多.那就是有任何方式/工具,我可以通过它,堆栈限制正在耗尽..再次,因为这是一个巨大的库文件而不是由我创建,我不完全清楚到哪里事情可能会出错.. (6认同)
  • 您的代码运行相同的低效段134217728次.不开玩笑.您应该使用按位运算符,以便将9级循环展开为一个循环级别. (5认同)
  • @Akhoy在常规函数中是的,但想想一个递归函数.它调用另一个(本身)并将前者的返回地址留在堆栈上(否则PC会在哪里知道去哪里?)这当然会再次调用自己,每次都将返回地址压入堆栈.当由于在下个世纪不太可能满足的基本情况而失控时,会出现堆栈溢出. (4认同)
  • @Oliver - 你可能想要研究动态编程 - 我猜你没有那么多独特的解决方案,你正在重复步骤,所以你可能需要将它编程为多项式时间而不是二次方.http://en.wikipedia.org/wiki/Dynamic_programming (3认同)
  • @ghayes 你在一条 5 年前的评论中标记我,该评论似乎指的是一条现已删除的评论,所以答案是“不知道,但当时有 30 人同意我的观点”。 (3认同)

luc*_*nik 78

如果你不小心导入/嵌入相同的JS文件两次,你有时可以得到这个,值得在检查员的资源选项卡中检查:)

  • 当您意外导入/嵌入相同的JS文件两次时,通常会发生此问题.引起递归循环的确切过程并不是我想要推测的,但是我认为这就像是通过相同的收费网关以100mph的速度驾驶两辆相同的汽车. (8认同)
  • 我不认为是这种情况.如果嵌入了两种相同类型的函数或变量,后者将覆盖先前的定义. (3认同)

FKa*_*asa 45

就我而言,我发送输入元素而不是它们的值:

$.post( '',{ registerName: $('#registerName') } )
Run Code Online (Sandbox Code Playgroud)

代替:

$.post( '',{ registerName: $('#registerName').val() } )
Run Code Online (Sandbox Code Playgroud)

这冻结了我的Chrome标签,甚至没有向我显示页面变得无法响应的"等待/终止"对话框...

  • 我不知道为什么这样的错误没有例外...谢谢! (3认同)

Aar*_*lla 29

在代码中的某处有一个递归循环(即一个函数最终会一次又一次地调用自己,直到堆栈已满).

其他浏览器要么有更大的堆栈(所以你得到超时)或者他们因某种原因吞下错误(可能是一个糟糕的try-catch).

发生错误时,使用调试器检查调用堆栈.


Sim*_*ver 12

检测堆栈溢出的问题有时堆栈跟踪将展开,您将无法看到实际发生的情况.

我发现Chrome的一些较新的调试工具对此非常有用.

点击Performance tab,确保Javascript samples已启用,你会得到这样的东西.

这里的溢出很明显!如果你点击,extendObject你将能够真正看到代码中的确切行号.

在此输入图像描述

您还可以查看可能有用或无用的时间或红鲱鱼.

在此输入图像描述


如果你实际上找不到问题,另一个有用的技巧是console.log在你认为问题所在的位置放置很多语句.上面的上一步可以帮助您.

在Chrome中,如果您重复输出相同的数据,它将显示如下,以显示问题更清楚的位置.在这种情况下,堆栈在最终崩溃之前达到7152帧:

在此输入图像描述


Nat*_*enn 12

在我的例子中,我使用以下内容将大字节数组转换为字符串:

String.fromCharCode.apply(null, new Uint16Array(bytes))
Run Code Online (Sandbox Code Playgroud)

bytes 包含数百万个条目,这些条目太大而无法放入堆栈中.

  • @KarthikHande您必须在for循环中而不是在一次调用中执行此操作.`var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte){converted.push(String.fromCharCode(byte))});` (6认同)

ben*_*ree 8

这也可能导致Maximum call stack size exceeded错误:

var items = [];
[].push.apply(items, new Array(1000000)); //Bad
Run Code Online (Sandbox Code Playgroud)

同样在这里:

items.push(...new Array(1000000)); //Bad
Run Code Online (Sandbox Code Playgroud)

来自Mozilla 文档

但要注意:以这种方式使用 apply 时,您可能会面临超出 JavaScript 引擎参数长度限制的风险。应用具有太多参数(考虑超过数万个参数)的函数的后果因引擎而异(JavaScriptCore 硬编码参数限制为 65536),因为该限制(实际上甚至是任何过大堆栈的性质)行为)未指定。有些引擎会抛出异常。更有害的是,其他人会任意限制实际传递给应用函数的参数数量。为了说明后一种情况:如果这样的引擎有四个参数的限制(实际限制当然要高得多),则就好像参数 5、6、2、3 已被传递以应用于上面的示例中,而不是完整的数组。

所以尝试:

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


Sha*_*dat 6

就我而言,click事件正在子元素上传播.所以,我必须提出以下内容:

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");
 });
Run Code Online (Sandbox Code Playgroud)

这是html代码:

 <div class="current-code">                                      
      <input type="submit" name="removediscountcouponcode" value="
title="Remove" class="remove-discount-button">
   </div>
Run Code Online (Sandbox Code Playgroud)


Nan*_*yle 6

就我而言,我有两个同名的变量!


chi*_*him 5

检查Chrome开发工具栏控制台中的错误详细信息,这将为您提供调用堆栈中的功能,并引导您进行导致错误的递归.


小智 5

如果由于某种原因需要运行无限进程/递归,则可以在单独的线程中使用webworker. http://www.html5rocks.com/en/tutorials/workers/basics/

如果你想操纵dom元素并重绘,请使用动画 http://creativejs.com/resources/requestanimationframe/


Ama*_*man 5

就我而言,我基本上忘记了value获取input.

错误的

let name=document.getElementById('name');
param={"name":name}
Run Code Online (Sandbox Code Playgroud)

正确的

let name=document.getElementById('name').value;
param={"name":name}
Run Code Online (Sandbox Code Playgroud)