当前位置: 首页 > 知识库问答 >
问题:

节点.js - 已超出最大调用堆栈大小

洪俊拔
2023-03-14

当我运行代码时,Node。js抛出由过多递归调用引起的“RangeError:Maximum call stack size exceeded”异常。我试图增加Node。js-stack-size-bysudo-node--stack-size=16000-app,但是node。js崩溃,没有任何错误消息。当我在没有sudo的情况下再次运行时,请选择Node。js打印“Segmentation fault:11”。有没有可能在不删除递归调用的情况下解决这个问题?

共有3个答案

金高飞
2023-03-14

在某些语言中,这可以通过尾调用优化来解决,其中递归调用在后台转换为循环,因此不存在达到最大堆栈大小的错误。

但是在javascript中,目前的引擎不支持这一点,这是为语言Ecmascript 6的新版本预见的。

节点。js有一些标志可以启用ES6功能,但尾调用尚不可用。

因此,您可以重构代码以实现称为蹦床的技术,或者重构以将递归转换为循环。

鞠边浩
2023-03-14

我发现了一个肮脏的解决方法:

/bin/bash -c "ulimit -s 65500; exec /usr/local/bin/node --stack-size=65500 /path/to/app.js"

它只是增加了调用堆栈限制。我认为这不适合生产代码,但我需要它来编写只运行一次的脚本。

谭浩皛
2023-03-14

您应该将递归函数调用包装为

  • 设置超时
  • set即时
  • process.nextTick

函数给node.js清除堆栈的机会。如果你不这样做,并且有许多循环没有任何真正的异步函数调用,或者如果你不等待回调,你的RangeError:超过最大调用堆栈大小将是不可避免的。

有很多关于“潜在异步循环”的文章。这里有一个。

现在有更多的示例代码:

// ANTI-PATTERN
// THIS WILL CRASH

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            // this will crash after some rounds with
            // "stack exceed", because control is never given back
            // to the browser 
            // -> no GC and browser "dead" ... "VERY BAD"
            potAsyncLoop( i+1, resume ); 
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});

这是正确的:

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            // Now the browser gets the chance to clear the stack
            // after every round by getting the control back.
            // Afterwards the loop continues
            setTimeout( function() {
                potAsyncLoop( i+1, resume ); 
            }, 0 );
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});

现在你的循环可能变得太慢了,因为我们每一轮都损失了一点时间(一次浏览器往返)。但是您不必在每一轮都调用< code>setTimeout。一般来说,每1000次就可以了。但这可能会因您的堆栈大小而有所不同:

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            if( i % 1000 === 0 ) {
                setTimeout( function() {
                    potAsyncLoop( i+1, resume ); 
                }, 0 );
            } else {
                potAsyncLoop( i+1, resume ); 
            }
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});
 类似资料:
  • 问题内容: 我有一台服务器,可能导致以下输出死亡: 但是,如果没有堆栈转储或跟踪,就无法确定这是无限递归还是只是链太大而已,更不用说问题函数在哪里了。 使用该选项运行Node 不仅使我的测试运行缓慢(正如人们期望的那样),而且没有重现该问题。 有人有任何解决方案或提示来深入了解此问题吗? 问题答案: 看来目前的答案是:站稳脚步,等待Node.js更新到新的V8版本,或者使用此Chromium项目错

  • 问题内容: 当我运行我的代码时,Node.js引发由过多的递归调用引起的异常。我试图将Node.js堆栈大小增加,但是Node.js崩溃而没有任何错误消息。当我不使用sudo再次运行此命令时,Node.js将输出。是否有可能在不删除递归调用的情况下解决此问题? 问题答案: 您应该将递归函数调用包装到 , 要么 函数使node.js有机会清除堆栈。如果您不这样做,并且有很多循环没有任何 真正的 异步

  • 问题内容: 我想这意味着有一个循环引用,但是对于我的一生,我无法猜测如何解决它。 有人有主意吗? http://plnkr.co/edit/aNcBcU?p=预览 检查Chrome中的调试控制台(例如),您将看到错误。冒犯的行是 通过以下方式在控制器上对scope.map进行“ $ watched” 问题答案: 这是因为您要比较对象是否相等,而不是参考。将您的声明更改为此:

  • 如果用户未登录,我尝试将用户重定向到“TrapPage”。 这是我的代码: 当我将函数requireAuth放在onEnter上时,控制台给我一个错误: 我是一个反应迟钝的人,请耐心点:) 我的代码有什么问题?

  • 在我的插座里。io应用程序,我正在尝试将房间中的一组用户发送到客户端,以便创建一个显示房间中所有用户的元素。文档中说,您可以使用以下代码返回给定命名空间和文件室中的所有套接字实例: 但是,它涉及到,这是我不太熟悉的。我只是把代码块放在一个函数中,我不确定这是最好的方法。 当我尝试运行此操作时,控制台中出现以下错误: 我试着对此做了一些研究,发现了这个答案,建议将代码包装在块中。我已经做到了: 但是

  • 我正在使用我岳父让我建立的一个网站作为学习React的借口。我不是一个天生的JavaScript开发人员(更喜欢后端),我知道我下面的代码中可能有一些递归元素,但我就是看不到。谁能告诉我我做错了什么?