首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >修改当前引用导致超过最大堆栈大小的崩溃

修改当前引用导致超过最大堆栈大小的崩溃
EN

Stack Overflow用户
提问于 2017-02-15 01:11:36
回答 2查看 170关注 0票数 0

在node js中,使用版本4.1.0的'firebase-admin‘SDK,我有一个监听程序,它监听数据库中的消息队列引用,处理消息,然后尝试将其从队列引用中删除。

在启动脚本之前,如果队列中的记录数超过一定数量(我的机器上有1354条记录),脚本就会崩溃,并出现超过最大调用堆栈的错误。

奇怪的是,只有在脚本启动前队列中有1354+值时,才会发生这种情况。任何低于此值的值,问题都会消失。

我不知道为什么会发生这种情况,但我知道只有当我试图修改/删除快照引用处的对象时,才会发生这种情况。

这是一个自包含的mcve,在注释中标出了问题区域:

代码语言:javascript
运行
复制
var admin = require("firebase-admin");

var serviceAccount = require("<ADMIN JSON FILE PATH GOES HERE>");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "<FIREBASE URL GOES HERE>"
});

var ref = admin.database().ref();

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// the number of messages to generate for the queue. when this is >= 1354 (on my machine) the program crashes, if it's less than that,
// it works perfectly fine; your tipping point may vary
var amount = 1354;
// message payload to deliver to the queue <amount> times
var payload = {};

// message generation loop
for (i = 0; i < amount; i++) {
    var message = {msg: "hello"};
    payload['message-queue/' + ref.push().key] = message;
}

// add the generated messages simultaneously to message-queue
ref.update(payload).then(function () {

    // 'on child added' listener that causes the crash of the program when there are 1354+ pre-existing messages in the queue prior to application start
    ref.child('message-queue').on('child_added', function(snapshot) {

        var msgKey = snapshot.key;
        var msgContents = snapshot.val().msg

        // do something with msgContents (e.g. sanitize message and deliver to some user's message-received node in the firebase)

        // ***THIS*** is what causes the crash. if you remove this line of code, the program does not crash. it seems that any
        // modification/removal to/of the current <msgKey> node does the same
        ref.child('message-queue').child(msgKey).remove();
    });
});

下面是崩溃的堆栈跟踪:

代码语言:javascript
运行
复制
FIREBASE WARNING: Exception was thrown by user callback. RangeError: Maximum call stack size exceeded

    at RegExp.exec (native)
    at RegExp.test (native)
    at tc (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63:86)
    at ub (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:60:136)
    at vb (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:43:1228)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:44)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)

<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63
(d="0"+d),c+=d;return c.toLowerCase()}var zc=/^-?\d{1,10}$/;function tc(a){retur
n zc.test(a)&&(a=Number(a),-2147483648<=a&&2147483647>=a)?a:null}function Ac(a){
try{a()}catch(b){setTimeout(function(){N("Exception was thrown by user callback.
",b.stack||"");throw b;},Math.floor(0))}}function Bc(a,b,c){Object.definePropert
y(a,b,{get:c})}function Cc(a,b){var c=setTimeout(a,b);"object"===typeof c&&c.unr
ef&&c.unref();return c};function Dc(a){var b={},c={},d={},e="";try{var f=a.split
("."),b=bb(hc(f[0])||""),c=bb(hc(f[1])||""),e=f[2],d=c.d||{};delete c.d}catch(g)
{}return{wg:b,Ge:c,data:d,mg:e}}function Ec(a){a=Dc(a);var b=a.Ge;return!!a.mg&&
!!b&&"object"===typeof b&&b.hasOwnProperty("iat")}function Fc(a){a=Dc(a).Ge;retu
rn"object"===typeof a&&!0===y(a,"admin")};function Gc(a,b,c){this.type=Hc;this.s
ource=a;this.path=b;this.children=c}Gc.prototype.Jc=function(a){if(this.path.e()
)return a=this.children.sub

RangeError: Maximum call stack size exceeded
    at RegExp.exec (native)
    at RegExp.test (native)
    at tc (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63:86)
    at ub (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:60:136)
    at vb (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:43:1228)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:44)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136)

<MY_PROJECT_PATH>>

<MY_PROJECT_PATH>>

<MY_PROJECT_PATH>>
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-15 03:08:57

即使您没有处理它,对remove()的调用仍然是基于异步/promise的,并生成一个在其中运行的上下文。Promise上下文是相当大的,所以你在这里耗尽堆栈也就不足为奇了。如果您确实需要这样的模式才能正常工作,您可以批量更新-让child_added将值插入“要删除”的数组中,然后将该数组作为一个单独的任务一次处理一批条目,直到它为空。在BlueBird (http://bluebirdjs.com/)库中,有很多使用数组的辅助方法和承诺(例如map/mapSeries)可以对此有所帮助。

这并不是真正的Firebase问题-所有其他虚拟机(PHP、Java等)还需要处理堆栈大小限制。与大多数其他版本一样,V8的版本也是可调的,如果需要,您可以使用如下命令查询(并调整)它:

代码语言:javascript
运行
复制
node --v8-options | grep -B0 -A1 stack_size

但我相信你最好的方法是组织你的程序,以最小化这个删除模式的堆栈使用。增加堆栈大小总是会让你产生“现在足够大吗?”有个问题。

票数 1
EN

Stack Overflow用户

发布于 2017-12-13 09:58:58

在函数内部最小化分配给stack.for示例静态数组的内存,而不是使用动态数组。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42232175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档