使用Node.js的Firebase中的内存泄漏

时间:2019-01-20 14:14:34

标签: node.js firebase firebase-realtime-database

当尝试使用“ child_added”事件加载订单(2万个节点)时,Firebase出现问题。内存消耗增加,再也不会下降。一旦我停止了nodejs脚本,它就会恢复正常。

我的问题是(在启动时)我正在nodejs服务器上运行此脚本,因此,服务器上的内存增加了,再也没有减少了。

试图在检索“ orders”节点的所有子级之后生成内存的堆快照。它表明大多数内存分配都发生在对象内部:

  • LLRBNode => 30%
  • (string)=> 34%
  • LeafNode => 20%

基本上是“ sOrder” Firebase快照对象的成员。我的原始代码未使用“ global.gc”运行,但我添加了代码以确保垃圾收集器正在运行,并且在两种情况下,都发生了相同的内存问题。

我使用这样的脚本:

node --expose-gc orders_load.js

我不使用调试来重现这种情况。我的示例代码:

console.log( "starting... " );
try
{
    let i = 1;
    firebase.database().ref("orders").on( "child_added", ( sOrder ) =>
    {
        console.log( "** " + i++ );
        if ( global.gc )
        {
            if( i % 1000 == 0 )
            {
                console.log( "running garbage collector" );
                global.gc();
            }
        }
        else
            console.log( 'Garbage collection unavailable.' );
    } );
}
catch( err )
{
    console.log( `EXCEPTION-%s`, err.message );
}

我的“订单”节点有20K条记录,一旦我运行了上面的代码,可用内存就从2181 Mb下降到1426 Mb(755 Mb内存)。知道为什么即使对“ child_added”事件的回调函数完成后,我所有订单的快照对象似乎仍保留在内存中吗?

firebase-admin:6.4.0 nodejs:v11.6.0

=========================== 在应用了以下 Frank 的提示后,我得到了以下代码:

let i = 1;

function child_added( sOrder )
{
    console.log( "** " + i++ + " %s", sOrder.key );
}

console.log( "starting... " );
try
{
    firebase.database().ref("orders").once( "value", ( sOrders ) =>
    {
        sOrders.forEach( child_added );

        process.nextTick( () =>
        {
            firebase.database().ref("orders").limitToLast(1).on( "child_added", ( sOrder ) =>
            {
                child_added( sOrder );
            } );
        } );
    } );
}
catch( err )
{
    console.log( `EXCEPTION-%s`, err.message );
}

这有效,并且内存消耗消失了。因此,我收到了“订单”节点的所有子级+收到新的订单+内存不足!

1 个答案:

答案 0 :(得分:1)

当您附加on侦听器时,该侦听器将保持活动状态,直到您使用off将其删除为止。在侦听器处于活动状态时,Firebase会保留该侦听器收到的所有数据的内存中副本。此内存中副本/缓存的内存使用可能非常重要,因此,当您不再需要数据时,应该删除监听器。

要删除参考上的所有侦听器,请执行以下操作:

firebase.database().ref("orders").off();