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


532

我正在使用Direct Web Remoting(DWR)JavaScript库文件,并且仅在Safari(台式机和iPad)中出现错误

它说

超出最大呼叫堆栈大小。

该错误的确切含义是什么,它会完全停止处理吗?

也包括对Safari浏览器的任何修复(实际上在上iPad Safari

JS:执行超出超时

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


2
我在尝试通过dataajax 发送变量(未声明它们)时遇到此错误。通过声明变量修复了错误。
phpfresher

Answers:


620

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

这几乎总是因为没有满足基本情况的递归函数。

查看堆栈

考虑这段代码...

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

这是经过几次调用后的堆栈...

网页检查器

如您所见,调用堆栈会不断增长,直到达到极限:浏览器采用硬编码的堆栈大小或内存耗尽。

为了对其进行修复,请确保您的递归函数具有可以满足的基本情况。

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

6
对此有很多帮助。.因此,有什么方法/工具可以使堆栈限制用尽。.再次,因为这是一个巨大的库文件,不是我创建的,所以我不完全知道该在哪里事情可能会出错..
testndtv 2011年

52
@Oliver如果必须运行将近300万亿次的函数,则可能是做错了什么。
ceejayoz 2014年

3
@Oliver-您可能想研究动态编程-我的猜测是,您没有那么多独特的解决方案,您在重复步骤,因此您可能需要将其编程为多项式时间,而不是二次式。en.wikipedia.org/wiki/Dynamic_programming
newshorts

4
@Akhoy在常规函数中可以,但是请考虑递归函数。它调用另一个(自身),并将前者的返回地址留在堆栈中(否则PC会知道要去哪里?)当然,每次将返回地址推入堆栈时,它都会再次调用自身。当由于在下个世纪不太可能满足的基本情况而使此问题消失时,您会遇到堆栈溢出的情况。
Alex

5
您的代码运行相同的无效段134217728次。别开玩笑了。您应该使用按位运算符,以便可以将9个级别的循环展开为一个级别的循环。
杰克·吉芬

82

如果您不小心两次导入/嵌入相同的JavaScript文件,有时可以得到此文件,值得在检查器的“资源”选项卡中进行检查。


9
当您不小心两次导入/嵌入相同的JS文件时,通常会发生此问题。我不希望推测导致递归循环的确切过程,但是我认为这类似于通过相同的收费网关以100mph的速度驾驶两辆相同的汽车。
lucygenik

3
我认为情况并非如此。如果嵌入了两种相同类型的函数或变量,则后者将覆盖先前的定义。
ssudaraka

是的...我真的不知道为什么会发生或发生什么过程,尽管它也会覆盖它。
lucygenik

晚会晚了一点,但可以想象这是代码在任何函数之外的时候,两者都将在两个JS文件中执行,并且一个可能不会彼此覆盖,因为它们在任何函数之外。
Cillian Collins

1
@lucygenik下次您希望批准帖子上的巨魔编辑时要格外小心。这篇文章差点删除垃圾邮件(检查历史记录)
让·弗朗索瓦·法布尔

56

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

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

代替:

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

这使我的Chrome标签冻结,直到页面无响应时甚至没有显示“等待/杀死”对话框。


3
我不知道为什么这样的错误没有例外...谢谢!
Džuris

非常感谢,这救了我
Eme Hado

我正打算将其添加为可能的解决方案。我只是做了这个事情,哈哈
Michael Buchok,

30

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

其他浏览器要么堆栈更大(因此您会超时),要么由于某种原因(可能是错误放置的try-catch)吞没了错误。

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


非常感谢您的回复。在IE / FF上,代码似乎可以正常运行。.仅在台式机Safari和iPad Safari中,出现错误。其实JS文件不是我自己的创作,但它是一个库文件(从DWR的engine.js).. directwebremoting.org 同样,当你说“调试器来检查调用堆栈”,我该怎么做,使用Safari的督察?
testndtv 2011年

我没有使用Safari Inspector的经验。尝试打开JavaScript调试器并加载页面。引发未捕获的错误时,调试器应停止。如果这样不起作用,请询问超级用户或网站管理员(请参阅页面底部)
Aaron Digulla 2011年

有两个函数命名相同的东西!DOH!
jharris8567

16

检测stackoverflows的问题是有时堆栈跟踪会消失,您将无法看到实际情况。

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

点击Performance tab,确保Javascript samples已启用,您将获得类似的信息。

很明显这里有溢出!如果单击,extendObject您将可以在代码中实际看到确切的行号。

在此处输入图片说明

您还可以看到可能会有所帮助的时机,也可能会看到红鲱鱼。

在此处输入图片说明


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

在Chrome中,如果您重复输出相同的数据,它将像这样显示,以更清楚地指出问题所在。在这种情况下,堆栈在最终崩溃之前命中了7152帧:

在此处输入图片说明


13

就我而言,我正在使用以下命令将大字节数组转换为字符串:

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

bytes 包含数百万个条目,太大而无法容纳在堆栈中。


我在同一条线上也遇到了同样的问题!thanx
ksh

那么转换大字节数组的最佳解决方案是什么?
ksh

6
@KarthikHande您必须在for循环中进行此操作,而不是在一个调用中进行。var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn

我如何将其转换成JSON我试图JSON.parse但它没有工作...我使用Uintl8Array?
KSH

@KarthikHande我不能不看整个问题就知道。请用所有详细信息打开另一个问题。
Nate Glenn

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

我们最近在我们正在处理的管理网站中添加了一个字段-contact_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中

但要注意:以这种方式使用应用时,存在冒超出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]);
}

0

下面的相同代码的两个调用如果减少1,则在我的计算机上的Chrome 32中均可运行,例如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

我还面临类似的问题,这是使用下拉徽标上传框上传徽标时的详细信息

<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上使用过两次的字段名来解决了该问题,例如

    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");
});

您有两种选择可以避免这种情况:

  • 将孩子移到父母的外部。
  • stopPropagation函数应用于子元素。

0

我有这个错误,因为我有两个同名的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

遇到相同的问题,就没想到是什么原因开始怪Babel;)

使代码在浏览器中不返回任何异常:

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

我正在与(npm 6.9.0&node 10.16.1)一起使用React-Native 0.61.5

当我在Project中安装任何新库时,

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

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

为此,我尝试

sudo npm缓存清理--force

(注意:-以下命令通常需要1到2分钟的时间, 具体取决于您的npm缓存大小)


-1

有时由于转换数据类型而发生,例如,您有一个被视为字符串的对象。

例如,在js客户端中的nodejs中的nodejs中的socket.id不是字符串。要将其用作字符串,您必须在前面添加单词String:

String(socket.id);

-1

当未声明该变量时,我试图分配一个变量,即一个值。

声明变量修复了我的错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.