v8 存储一个字符串需要多少内存?

Jim*_*mmy 5 javascript memory v8

我正在尝试计算 v8 中字符串的内存使用情况,并且我知道单个字符将占用 2 个字节。但是当我在开发工具中检查浅层大小和保留大小时,我对结果感到困惑:

function Student() {
    this.name = 'lll';
}

var a = new Student();

var b = new String("ccccc");
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

浅层大小和保留大小都是 16 字节。为什么?

正如我想象的那样,浅层大小和保留大小将相等,并且该值将是 6 个字节。如果我将字符串从“lll”更改为“llll”,该值将增加 2 个字节。但它保持不变,如下所示:

在此输入图像描述

有人可以向我解释一下吗?

jmr*_*mrk 17

(这里是 V8 开发人员。)
前面的一般说明:字符串在 Web 上非常常见,因此 JavaScript 引擎竭尽全力为您可以使用字符串执行的许多不同操作实现许多不同的优化,因此,字符串处理系统在现代 JS 引擎中往往非常复杂。排除了这一点,我们可以在这里专注于“简单”字符串。

单个字符需要 2 个字节

还有更多内容:V8 在内部区分一字节和两字节字符串。当给定字符串中的所有字符都可以用一个字节表示时,那么(通常)V8 就会这么做。

浅层大小和保留大小都是 16 字节。为什么?

评论者已经发布了一个描述“浅”和“保留”大小之间差异的链接,所以我不会深入讨论。对于简单的字符串来说,它确实总是相同的值。

堆上的所有对象都以一个形状描述符开始,该描述符占用一个指针大小(由于 64 位平台上的“指针压缩”,现在通常为 4 个字节)。

字符串在其对象头中另外还有两个 4 字节的字段:字符串的哈希值(经常需要它,因此为了避免一直重新计算它,它被缓存在那里)和字符串的长度。

之后,他们存储实际的字符。任何堆对象的大小必须是指针大小的倍数,即4的倍数,因此字符串的大小向上舍入为该值;最后几个字节可能未使用。

因此,总而言之,包含nASCII 字符的简单字符串的大小为:

12 + 4 * Math.ceil(n/4)
Run Code Online (Sandbox Code Playgroud)

(这可能会随着时间的推移而改变,如果在构建时关闭指针压缩,情况会有所不同,当字符串中有两字节字符时,情况会有所不同,当字符串是“切片”时,情况会有所不同" 或 "cons" 字符串,当该字符串与 Blink 共享时,它会有所不同,而且我可能忘记了某些情况下它也会有所不同。)

如果您稍微扩展一下实验,您会看到:
""需要 12 个字节
"1""1234"需要 16 个字节
"12345""12345678"需要 20 个字节
"123456789"需要 24 个字节,依此类推。