我试图找出导致以下代码迭代期间内存使用量显着增加的原因。
async function a () {
for (let i = 0; i < 10000000000; i++) {
await new Promise(resolve => {
if (i%100000 === 0) {
console.log(i)
console.log(process.memoryUsage())
}
resolve(i)
})
}
}
a()
随着代码的运行,这种内存使用量跳跃会发生多次,并且总是在 i 达到某个特定数字时发生。
在 7.9.0 中,始终出现在 2000000 -> 2100000 之间
1700000
{ rss: 20135936, heapTotal: 9355264, heapUsed: 6003256, external: 8772 }
1800000
{ rss: 19836928, heapTotal: 9355264, heapUsed: 4490432, external: 8772 }
1900000
{ rss: 19316736, heapTotal: 9355264, heapUsed: 5039992, external: 8772 }
<-- Jump happens between here -->
2000000
{ rss: 19357696, heapTotal: 9355264, heapUsed: 5587808, external: 8772 }
2100000
{ rss: 23605248, heapTotal: 13549568, heapUsed: 6088208, external: 8772 }
<-- and here -->
2200000
{ rss: 23601152, heapTotal: 13549568, heapUsed: 6586000, external: 8772 }
2300000
{ rss: 23568384, heapTotal: 13549568, heapUsed: 7083112, external: 8772 }
在 8.3.0 中,始终出现在 2600000 -> 2700000 之间
2400000
{ rss: 30507008, heapTotal: 9437184, heapUsed: 4785896, external: 8252 }
2500000
{ rss: 30523392, heapTotal: 9437184, heapUsed: 4710912, external: 8252 }
<-- Jump happens between here -->
2600000
{ rss: 30539776, heapTotal: 9437184, heapUsed: 4636176, external: 8252 }
2700000
{ rss: 34742272, heapTotal: 13631488, heapUsed: 6606512, external: 8252 }
<-- and here -->
2800000
{ rss: 34750464, heapTotal: 13631488, heapUsed: 8571208, external: 8252 }
2900000
{ rss: 34758656, heapTotal: 13631488, heapUsed: 6412304, external: 8252 }
最佳答案
在 V8(Node.js 使用的 JS 运行时)中,为堆预先分配了一定的大小。这就是您看到的 heapTotal
。当 V8 怀疑您将需要更多空间时,它会增加堆的总大小。
在您的示例代码中,会发生很多小对象在堆上分配的情况。这反射(reflect)在 heapUsed
中,并且是代码正在使用的实际内存量。当堆填满时,将执行一轮垃圾收集 (GC),以释放空间。因此,如果您在增加 i
时绘制 heapUsed
,那么您会看到它不断上升,直到 GC 启动并且它会回落。
事实上,这正是我非常长期所做的事情!
您可以清楚地看到,在 GC 启动之前,堆永远不允许变得那么大。
为了进一步验证这一点,如果我们使用 node --expose_gc
运行以下命令,我们可以在代码中手动触发 GC
async function run() {
for (let i = 0; i < 10000000000; i++) {
await new Promise(async resolve => {
if (i % 10000000 === 0) {
global.gc();
console.log(`${i}, ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)}mb`);
}
resolve();
});
}
}
run();
由此您可以在 v7.9.0
上获得以下输出
0, 3.12mb
10000000, 2.77mb
20000000, 2.78mb
30000000, 2.78mb
40000000, 2.78mb
50000000, 2.78mb
60000000, 2.78mb
不同的 Node 版本
非常有趣的是,如果我们在不同版本的 Node 上运行测试!
正如您所看到的,v8.2.0 之前的版本和后续版本的 Node.js 的内存配置文件存在巨大差异。如果我们去看看change log对于 v8.3.0,我们明白原因了!
The V8 engine has been upgraded to version 6.0, which has a significantly changed performance profile
这是包含 Turbofan 的 V8 版本它实现了 Node 海,并包括许多 GC 性能增强。
Thorsten Lorenz 的 v8-perf 中提供了有关 V8 GC 如何工作的更深入的 View 。 repo 协议(protocol)。
关于node.js - 在异步函数中迭代 Promise 时内存使用量显着增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55241904/