2014-11-22 37 views
6

寻求nodejs专家对使用承诺的帮助。我有以下测试程序,其中我调用异步“q”函数,只是抛出一个异常。这个程序相当一致地泄漏内存;但如果取消注释.done()调用,泄漏消失。Nodejs - 承诺,未处理的终止和内存泄漏

为什么泄漏发生在承诺未终止时(即没有完成()调用)?我试图遵循documentation,但无法理解done()方法的解释。在此先感谢您的帮助!

这里是我的代码:

(function() { 
    var MAX_ITER_COUNT, Q, iterCount, maxMem, noop, qDoit, test; 

    Q = require("q"); 

    iterCount = 0; 

    MAX_ITER_COUNT = 10 * 1000; 

    maxMem = 0; 

    noop = function() {}; 

    qDoit = function() { 
    var currentMem; 
    currentMem = Math.round(process.memoryUsage().heapUsed/1024/1024); 
    if (currentMem > maxMem) { 
     maxMem = currentMem; 
    } 
    console.log("" + iterCount + " - memory is: " + currentMem + "/" + maxMem + " MB"); 
    return Q(10).then(function() { 
     throw new Error("X"); 
    }); 
    }; 

    test = function() { 
    if (iterCount++ > MAX_ITER_COUNT) { 
     console.log("DONE"); 
     return; 
    } 

    // ---- If I uncomment the done() call below the leak goes away ---- 
    return qDoit()["finally"](function() { 
     return setImmediate(test); 
    }) 
    //.done(noop, noop, noop); 


    }; 

    Q.onerror = function() {}; 

    test(); 

}).call(this); 
+0

您是如何确定发生内存泄漏的?也只是好奇,任何理由你把这整个事情包装在一个匿名函数中? – 2014-11-22 18:18:17

+0

@torazaburo - 打印内存使用情况报告的console.log调用使用.done()调用非常不变的内存使用情况,但在注释掉.done()时一直增长。匿名函数 - 这是由咖啡脚本编译器生成的,它产生这种风格的代码来正确地为变量作用域,避免全局名称冲突等。 – PKK 2014-11-22 18:28:20

+0

@torazaburo - 这应该不是问题,因为测试函数是通过setImmediate()呼叫。 – PKK 2014-11-22 19:10:56

回答

5

回答我的问题,希望这将帮助别人。

在挖掘一下q库代码后,它看起来像所有未处理的异常都放在一个名为unhandledRejections的数组中,默认情况下。不知道为什么它是这样实现的,但大概是为了帮助开发人员追踪未处理的异常。通过调用Q.stopUnhandledRejectionTracking()可以更改此行为。当我这样做时,即使没有拨打.done(),内存泄漏也会消失。

+1

未处理的拒绝数组似乎是用于单元测试的目的:https://github.com/kriskowal/q/issues/265 – PKK 2014-11-24 19:21:23