【发布时间】:2020-03-21 11:27:07
【问题描述】:
我发现 V8 对象有相当多的内存开销:我有一个大部分是空对象的数组;每个元素需要高达 64 个字节。 (相比之下,Java 需要 16 个字节。)
$ node --expose-gc -e '
gc();
const start = process.memoryUsage().heapUsed;
var a = Array(50 * 1000);
for (let i = 0; i < a.length; i++) a[i] = {};
gc();
console.log(process.memoryUsage().heapUsed - start)
'
3231304
然后我发现我可以通过向我的对象添加一个虚拟属性来减少 37% 的内存使用量。
$ node --expose-gc -e '
gc();
const start = process.memoryUsage().heapUsed;
var a = Array(50 * 1000);
for (let i = 0; i < a.length; i++) a[i] = {lifeTheUniverseAndEverything:42};
gc();
console.log(process.memoryUsage().heapUsed - start)
'
2028440
为什么向我的对象添加属性会减少我的内存使用量?
$ node -v
v12.7.0
$ uname -a
Linux paul 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
【问题讨论】:
-
在带有节点 v8.12.0 的 macOS 10.14 上验证。更奇怪的是:如果我们在循环中执行
{ var c = "xxxx" + i + "xxxx"; a[i] = {c:42}; },它需要 2271136 字节 - 但如果我们执行{ var c = "xxxx" + i + "xxxx"; a[i] = {c:c}; }突然它需要 5860328 字节!我最初认为这可能与 V8 的对象形状优化有关,但这些结果让我质疑...... -
@nneonneo 第二个结果并不令人惊讶,因为您存储了许多(不同的)~15 个字符的字符串。 100k 元素额外 30 字节...额外 3MB。
-
这很有趣,因为这两种情况下的 keys 都是必须存储的大字符串 - 但它们不会对大小产生可衡量的影响。跨度>
-
@nneonneo,我想你的意思是写
{[c]:42}作为第一个例子,而不是{c:42}。 -
哦,我的错。我的 JS 明显生锈了 - 是的,我想要
[c]:42。这使得结果更符合预期,所以现在我确信我有正确的答案(如下)。
标签: node.js optimization memory v8 jit