被一个关于 promise 内存泄漏的问题所困扰,希望大家可以帮忙解惑~
'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();
与 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();
与 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();
1
bearice 2016-06-22 17:49:10 +08:00
|
4
xuzicn 2016-06-22 19:02:06 +08:00
并没有泄露啊
第一个代码不停的在压栈,不停的在构建执行上下文而且不释放。 第二个代码释放得很干净 第三个压栈的速度只有第一个压栈的一半。 |
5
mcfog 2016-06-22 19:18:21 +08:00
用很多内存和内存泄露是两回事情啊
内存泄露是“该回收没回收”,这段代码只是构造了“很长的调用栈,大量信息不该回收”的场景而已,算不上内存泄露。 |
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 要等两个,开销应该也小很多。 |
7
iceiceshen24 OP @bearice 你这个指令好厉害,受教了~但是我试了一遍你这个指令,发现 C 占用内存是一直没有变得呀,弱弱地说一哈之前一直用 top 看内存泄漏
|
8
breeswish 2016-06-23 10:38:25 +08:00
|
9
iceiceshen24 OP @breeswish 这个我感觉他没讲清楚
|
10
xuzicn 2016-06-23 13:59:21 +08:00
|
11
iceiceshen24 OP @xuzicn nice !
|
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(); }); })(); |
14
iceiceshen24 OP @xuzicn 3Q~~
|
15
poke707 2016-11-28 21:37:06 +08:00
看 co 的一些代码发现 https://github.com/tj/co/issues/180
在一些内部是死循环的生成器中,相当于楼主的例子,是可以永远不 resolve / reject 的。那么 A 中串联的所有 promise 都得不到释放了, B 只有外层一个 promise 没有释放。 |