Nodejs 求解一个 promise 内存泄漏问题
Nodejs 求解一个 promise 内存泄漏问题
被一个关于 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();
弱弱问问这个是怎样测试的
node --log_gc --trace_gc test.js
并没有泄露啊
第一个代码不停的在压栈,不停的在构建执行上下文而且不释放。
第二个代码释放得很干净
第三个压栈的速度只有第一个压栈的一半。
用很多内存和内存泄露是两回事情啊
内存泄露是“该回收没回收”,这段代码只是构造了“很长的调用栈,大量信息不该回收”的场景而已,算不上内存泄露。
我也觉得应该是用了很多内存而不是泄露,初学 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 要等两个,开销应该也小很多。
你这个指令好厉害,受教了~但是我试了一遍你这个指令,发现 C 占用内存是一直没有变得呀,弱弱地说一哈之前一直用 top 看内存泄漏
这个我感觉他没讲清楚
他这个文章有错。一会我补一篇来讲明问题
你的前半段理解我认同,后面的也有不准确的地方
nice !
懒得写文了,只需要在他的 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 ® {
global.gc()
console.log(111)
printMemory();
});
})();
3Q, 明天试试
3Q~~
看 co 的一些代码发现 https://github.com/tj/co/issues/180
在一些内部是死循环的生成器中,相当于楼主的例子,是可以永远不 resolve / reject 的。那么 A 中串联的所有 promise 都得不到释放了, B 只有外层一个 promise 没有释放。
在Node.js中,处理Promise时内存泄漏通常是由于未正确管理资源(如未释放的事件监听器、未解决的Promise链等)引起的。以下是一些常见的内存泄漏原因及解决策略,并附上简单的代码示例。
常见原因及解决策略
-
未解决的Promise: 如果Promise链中的某个环节没有正确处理(即没有
.then()
、.catch()
或.finally()
),可能会导致内存泄漏。function fetchData() { return new Promise((resolve, reject) => { // 模拟异步操作 setTimeout(() => resolve('data'), 1000); }); } fetchData() .then(data => { console.log(data); }) .catch(err => { console.error(err); // 确保捕获错误 });
-
未释放的事件监听器: 在Promise中注册的事件监听器如果没有在适当的时候移除,也可能导致内存泄漏。
const EventEmitter = require('events'); const emitter = new EventEmitter(); function createListener() { const listener = () => console.log('Event triggered'); emitter.on('event', listener); // 确保在不再需要时移除监听器 return () => emitter.removeListener('event', listener); } const cleanup = createListener(); // 在适当的时候调用cleanup() cleanup();
确保所有Promise都被正确处理,并适时移除不再需要的事件监听器,是防止Node.js应用中Promise内存泄漏的关键。