【问题标题】:Javascript heap out of memory errorJavascript堆内存不足错误
【发布时间】:2017-10-10 21:05:30
【问题描述】:

我正在尝试运行以下 while 循环,但由于某种原因出现 JS 堆内存不足错误:

 while( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i].pbpDetails[p]) == 'undefined') {
    //create time delay of one second
    setTimeout(function(){
        //put code to run after delay here
        if( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i+1].pbpDetails[0]) != 'undefined') {
            //this will run if the next inning has come through
            i = i+1;
            p = 0;
        }
            //this will also pass the while loop and go down to the actual code
    }, 3000);
}

我知道逻辑有缺陷,但现在我只在 if 语句为真的情况下运行它。

我收到以下错误:

11450 ms: Mark-sweep 1388.5 (1433.0) -> 1388.5 (1445.0) MB, 834.3 / 0.0 ms (+ 0.0 ms in 63 steps in 63 steps since the start of marking, max step 0.0 ms) [分配失败] [清除可能不会成功]。 12374 毫秒:标记扫描 1400.2 (1445.0) -> 1400.3 (1445.0) MB,910.6 / 0.0 毫秒(自标记开始以来的 188 步中 + 0.1 毫秒,最大步长 0.0 毫秒)[分配失败] [清除可能不会成功]。

<--- JS stacktrace --->
Cannot get stack trace in GC.
FATAL ERROR: MarkCompactCollector: semi-space copy, fallback in old gen Allocation failed - JavaScript heap out of memory
 1: node::Abort() [/usr/local/bin/node]
 2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/usr/local/bin/node]

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    我认为这不会达到您的预期。 setTimeout 获取您传递给它的函数,并在延迟之后将该函数添加到堆栈中的所有其他内容之后。由于 while 循环阻塞,您最终会遇到一种奇怪的情况,延迟函数在 while 循环完成之前不会被调用。

    var x = 0;
    while (x<10) {
      x++;
      console.log('omg');
      setTimeout(function(){console.log('from timeout');},0);
    }

    您将在上面看到循环将继续,直到在任何setTimeouts 执行之前完成。如果你的循环是无限的,那么它会创建一个巨大的调用堆栈,这些调用需要在未来发生但不能因为它们被循环阻塞。

    如果我不得不猜测,您似乎正在实施某种长轮询。如果那个东西是同步的(似乎不是),那么轮询它可能会更容易。如果不是,那么您将不得不考虑异步处理此问题。无论是回调、事件还是承诺。

    在您等待某事发生的情况下,事件通常是您的朋友。您可以创建自定义事件或使用框架来帮助您传播。

    【讨论】:

    • 对,关闭当前调用堆栈。在调用堆栈为空之前它无法运行。 @乔纳斯
    • @Jonasw 我不会声称我使用了所有正确的词。更多的是我如何理解它。我的主要观点是,如果循环继续,延迟函数将永远不会被调用。
    • @Jonasw 感谢您的评论!我更新了答案以尝试更具描述性
    【解决方案2】:

    如果延迟函数中的 i = i+1; 是您的代码中 i 更改的唯一位置,那可能会解释它。您的代码将不断重复并为setTimeout 创建计时器数千次,因为i 只能在 3 秒后更改(这将推进循环)(假设计时器没有被所有正在创建的计时器的负载延迟) ,它可能会是)。

    您需要重构此代码以不在循环中使用setTimeout

    【讨论】:

      【解决方案3】:

      根据KarlReids 的回答(很好的解释),您可能想试试这个:

      var i=0;
      while( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i].pbpDetails[p]) == 'undefined' && i<=apiResults[0].league.season.eventType[0].events[0].pbp.length) {
      setTimeout(function(i){//notice the bound i...
      
          if( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i+1].pbpDetails[0]) != 'undefined') {
              //some code
          }
      
      }, 3000,i);
      i = i+1;//increase in the main loop
      }
      

      或递归(一个接一个超时):

      (function loop(i){
          if( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i].pbpDetails[p]) == 'undefined' && i<=apiResults[0].league.season.eventType[0].events[0].pbp.length) {
              setTimeout(function(i){//notice the bound i...
      
                   if( typeof(apiResults[0].league.season.eventType[0].events[0].pbp[i+1].pbpDetails[0]) != 'undefined') {
                       //some code
                   }
                   //next
                  loop(i+1);
               }, 3000,i);
          }
      })(0);//start with zero
      

      【讨论】:

        猜你喜欢
        • 2020-08-07
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 2019-09-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-13
        • 2021-09-26
        相关资源
        最近更新 更多