Javascript比较内存中对象的大小

标签 javascript object v8

我在 JavaScript 中有大约一百万行,我需要为每行的元数据存储一个对象。给定以下两种不同的对象类型:

{0: {'e', 0, 'v': 'This is a value'}

还有:

{0: '0This is a value'}

一百万个第一类型的对象和一百万个第二类型的对象之间的内存有什么区别?即:

[obj1, obj1, obj1, ...] // array of 1M
[obj2, obj2, obj2, ...] // array of 1M

最佳答案

V8 开发人员在这里。答案仍然是“这取决于”,因为动态语言的引擎往往会适应你正在做的事情,所以一个很小的测试用例很可能不能代表真实应用程序的行为。一个永远适用的高级经验法则是:单个字符串比包装该字符串的对象占用更少的内存。少了多少?视情况而定。

也就是说,我可以针对您的具体示例给出具体答案。对于以下代码:

const kCount = 1000000;
let a = new Array(kCount);
for (let i = 0; i < kCount; i++) {
  // Version 1 (comment out the one or the other):
  a[i] = {0: {'e': 0, 'v': 'This is a value'}};
  // Version 2:
  a[i] = {0: '0This is a value'};
}
gc();

使用--expose-gc --trace-gc运行,我看到:

版本 1:244.5 MB

版本 2:206.4 MB

(接近最新的 V8、x64、d8 shell。这是 @paulsm4 建议您自己在 DevTools 中执行的操作。)

具体情况如下:

  • 数组本身每个条目需要 8 个字节
  • 从对象字面量创建的对象具有 3 个指针的 header 和为 4 个命名属性(此处未使用)预先分配的空间,总共 7 * 8 = 56 字节
  • 其索引属性的后备存储为 17 个条目分配空间,即使只使用一个条目,加上 19 个指针 = 152 字节的 header
  • 在版本 1 中,我们有一个内部对象,它检测到需要两个(且仅两个)命名属性,因此它的大小被 trim 为 5(3 个 header ,2 个表示“e”和“v”)指针 = 40字节
  • 在版本 2 中没有内部对象,只有一个指向字符串的指针
  • 字符串文字已进行重复数据删除,并且 0 直接作为“Smi”存储在指针中,因此这些都不需要额外的空间。

总结:

版本 1:8+56+152+40 = 每个对象 256 字节

版本 2:8+56+152 = 每个对象 216 字节

但是,如果并非所有字符串都相同,如果对象具有或多或少的命名或索引属性,如果它们来自构造函数而不是文字,如果它们增大或缩小,情况将会发生巨大的变化在他们的一生中,以及许多其他因素。坦率地说,我不认为可以从这些数字中收集到任何特别有用的见解(具体来说,虽然它们可能看起来效率很低,但它们不太可能以这种方式在实践中发生——我敢打赌,您实际上并没有存储这么多零,并将实际数据包装到单个属性 {0: ...} 对象中看起来也不现实)。

让我们看看!如果我从小测试中删除所有明显冗余的信息,同时强制为每个条目创建一个新的、唯一的字符串,我将留下这个循环来填充数组:

for (let i = 0; i < kCount; i++) {
  a[i] = i.toString();
}

总共仅消耗约 31 MB。更喜欢元数据的实际对象?

function Metadata(e, v) {
  this.e = e;
  this.v = v;
}
for (let i = 0; i < kCount; i++) {
  a[i] = new Metadata(i, i.toString());
}

现在我们的大小约为 69 MB。正如您所看到的:巨大的变化;-)

因此,要确定实际的完整应用程序及其任何实现替代方案的内存要求,您必须自己进行测量。

关于Javascript比较内存中对象的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58631581/

相关文章:

javascript - Chatango 嵌入代码的 W3C 验证器错误

java - java.lang.Object 的 protected 方法如何免受子类的影响?

eclipse - 如何在 Eclipse 的 Debug模式下更改端口?

c++ - v8::Script::Compile(v8::String::New (".make.some.syntax.errors"), v8::String::New ("main"))->Run() 导致段错误

javascript - 为什么向我的 const 添加两个 if 语句会引发错误

javascript - 如何在 Leaflet openPopup 中设置各种选项?

javascript - 删除 ul 元素左侧的多余空格

一个类的实例的Javascript数组

javascript - JS : how to convert a string to JS Object (**NOT** to JSON)?

c++ - JS2C到底是什么?