求解一个 promise 内存泄漏问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iceiceshen24
V2EX    Node.js

求解一个 promise 内存泄漏问题

  •  
  •   iceiceshen24 2016-06-22 17:10:03 +08:00 6514 次点击
    这是一个创建于 3428 天前的主题,其中的信息可能已经有所发展或是发生改变。

    被一个关于 promise 内存泄漏的问题所困扰,希望大家可以帮忙解惑~

    A 内存泄漏

    'use strict'; var i = 0; function run() { return new Promise(function(resolve) { i++; setTimeout(function() { if (i === 10000 * 10) return resolve(); resolve(run()); }, 0); }) .then(function() {}); } run(); 

    B 内存不泄露

    与 A 相比即将 function run()中的第一个 return 去掉。

    'use strict'; var i = 0; function run() { new Promise(function(resolve) { i++; setTimeout(function() { if (i === 10000 * 10) return resolve(); resolve(run()); }, 0); }) .then(function() {}); } run(); 

    C 内存不泄露

    与 A 相比将中的.then(function() {})去掉。

    'use strict'; var i = 0; function run() { return new Promise(function(resolve) { i++; setTimeout(function() { if (i === 10000 * 10) return resolve(); resolve(run()); }, 0); }); } run(); 
    15 条回复    2016-11-28 21:37:06 +08:00
    bearice
        1
    bearice  
       2016-06-22 17:49:10 +08:00
    C 并不是不泄露,只是泄露的少吧

    https://gist.github.com/bearice/ac52f65e4a1b22c7074e0a2e2d818967
    kenshinhu
        2
    kenshinhu  
       2016-06-22 17:52:50 +08:00
    @bearice 弱弱问问这个是怎样测试的
    bearice
        3
    bearice  
       2016-06-22 17:58:38 +08:00
    @kenshinhu node --log_gc --trace_gc test.js
    xuzicn
        4
    xuzicn  
       2016-06-22 19:02:06 +08:00
    并没有泄露啊
    第一个代码不停的在压栈,不停的在构建执行上下文而且不释放。
    第二个代码释放得很干净
    第三个压栈的速度只有第一个压栈的一半。
    mcfog
        5
    mcfog  
       2016-06-22 19:18:21 +08:00
    用很多内存和内存泄露是两回事情啊

    内存泄露是“该回收没回收”,这段代码只是构造了“很长的调用栈,大量信息不该回收”的场景而已,算不上内存泄露。
    Sparetire
        6
    Sparetire  
       2016-06-22 23:24:12 +08:00
    我也觉得应该是用了很多内存而不是泄露,初学 Promise ,回忆一下死去的操作系统和编译原理知识。。不知道对不对哈。
    记得 Promise A+规范是说 resolve 的参数如果是一个 Promise 会等这个状态完成。
    对于 AC, 每一个 run 都要等待下一个 run 的 Promise 的状态及它的 then 的状态确定下来,应该是一直不停压栈直到最后一个 run 执行完才退栈,而 B 的 run 没有 return ,等于是 resolve(undefined),每一个 run 执行完,里面的 Promise 的状态就确定了,执行完一个 run 就退一个栈而不用等到最后一个 run 执行完才退栈。
    而 A 和 C, 虽然都要等最后一个 run 执行完,但 C 每个 run 只要等一个 Promise 状态确定,而 A 要等两个,开销应该也小很多。
    iceiceshen24
        7
    iceiceshen24  
    OP
       2016-06-23 10:13:30 +08:00
    @bearice 你这个指令好厉害,受教了~但是我试了一遍你这个指令,发现 C 占用内存是一直没有变得呀,弱弱地说一哈之前一直用 top 看内存泄漏
    iceiceshen24
        9
    iceiceshen24  
    OP
       2016-06-23 10:40:43 +08:00
    @breeswish 这个我感觉他没讲清楚
    xuzicn
        10
    xuzicn  
       2016-06-23 13:59:21 +08:00
    @breeswish 他这个文章有错。一会我补一篇来讲明问题
    @Sparetire 你的前半段理解我认同,后面的也有不准确的地方
    iceiceshen24
        11
    iceiceshen24  
    OP
       2016-06-23 15:34:46 +08:00
    @xuzicn nice !
    xuzicn
        12
    xuzicn  
       2016-06-24 11:21:08 +08:00   1
    @iceiceshen24
    @breeswish
    @Sparetire

    懒得写文了,只需要在他的 A 段代码后,强制 gc 一次就可以看到区别。运行 node --expose-gc test.js ,最后一次 print 的内存比第二个 print 还少。


    (function() {
    function printMemory() {
    console.log(process.memoryUsage())
    }

    // 记录 Promise 链的长度
    var i = 0;
    function run() {
    return new Promise(function(resolve) {
    // 每增加 10000 个 Promise 打印一次内存使用情况
    if (i % 100 === 0) printMemory();
    i++;
    // 模拟一个异步操作
    setTimeout(function() {
    // 1000 个 Promise 之后退出
    if(i === 100 * 10) return resolve();
    // 如果 resolve 的参数是一个 Promise ,外层 Promise 将接管这个 Promise 的状态,构成嵌套 Promise
    resolve(run());
    }, 0);
    }).then(function() {
    // console.log(j);
    return true;
    });
    }
    run().then(function (r) {
    global.gc()
    console.log(111)
    printMemory();
    });
    })();
    Sparetire
        13
    Sparetire  
       2016-06-25 00:52:14 +08:00
    @xuzicn 3Q, 明天试试
    iceiceshen24
        14
    iceiceshen24  
    OP
       2016-06-30 10:46:33 +08:00
    @xuzicn 3Q~~
    poke707
        15
    poke707  
       2016-11-28 21:37:06 +08:00
    看 co 的一些代码发现 https://github.com/tj/co/issues/180

    在一些内部是死循环的生成器中,相当于楼主的例子,是可以永远不 resolve / reject 的。那么 A 中串联的所有 promise 都得不到释放了, B 只有外层一个 promise 没有释放。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1285 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 17:08 PVG 01:08 LAX 09:08 JFK 12:08
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86