javascript - Chrome 内存快照中的保留大小 - 究竟保留了什么?

标签 javascript google-chrome memory google-chrome-devtools v8

Chrome docs保留大小 是“一旦删除对象本身及其从 GC 根无法访问的依赖对象后释放的内存大小”,这很公平。然而,即使对于简单的对象,保留的大小通常是浅层大小的 3 倍。我知道 V8 需要存储对隐藏形状的引用,可能是一些用于 GC 的数据等,但有时对象有数百个额外的“保留”字节,当你需要拥有数百万个这样的对象时,这似乎是个问题。我们来看一个简单的例子:

class TestObject {
    constructor( x, y, z ) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

window.arr = [];
for ( let i = 0; i < 100000; i++ ) {
    window.arr.push( new TestObject( Math.random(), Math.random(), Math.random() ) );
}

这是内存快照:

Memory snapshot, shallow size is 24 bytes and retained size is 60 bytes

浅大小是 24 字节,这与我们存储 3 x 8 字节 double 的事实完全匹配。 “额外”大小为 36 字节,允许存储 9 x 4 字节指针(假设指针压缩已打开)。如果我们添加三个额外的属性,额外的大小将是 72 (!) 字节,所以它取决于属性的数量。那里存放着什么?是否有可能避免如此巨大的内存开销?

最佳答案

V8 开发人员在这里。

浅尺寸是对象本身,由标准对象头(3 个指针)和 3 个对象内属性组成,它们又是指针。那是 6 个(压缩的)指针,每个 4 个字节 = 24 个字节。

额外的保留大小是三个属性的存储。它们中的每一个都是一个“HeapNumber”,由一个 4 字节的映射指针和一个 8 字节的有效载荷组成。所以这是 3 个属性乘以 12 个字节 = 36 个字节。 (有了这些知识,如果再加上另外三个可能也是数字的属性,这应该是 72 的两倍。)

加起来,每个对象总共占用 24+36 = 60 个字节。

映射和原型(prototype)不计入每个对象的保留大小,因为它们由所有对象共享,因此释放一个对象不会允许它们也被释放。

节省内存的一个想法(如果您觉得它很重要)是“转置”您的数据组织:而不是 1 个数组包含 100,000 个对象,每个对象有 3 个数字,您可以有 1 个对象包含 3 个数组,每个数组有 100,000 个数字。根据您的用例,这可能是也可能不是一种可行的方法:如果三元组数字来来去去很多,那么将它们存储在一个巨大的数组中会令人不快;而如果它是一个静态数据集,那么两个模型在可用性上可能相当等效。如果这样做,您将避免重复的每个对象开销;此外,数组可以内联存储双数字(只要整个数组仅包含数字),因此您可以存储相同的 300K 数字,而总内存消耗仅为 2.4MB。

如果您尝试用许多小型 TypedArrays 替换 3 属性对象,您会发现内存使用量显着增加,因为 TypedArrays 每个对象的开销比简单对象大得多。它们旨在拥有一些大型阵列,而不是许多小型阵列。

关于javascript - Chrome 内存快照中的保留大小 - 究竟保留了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62049063/

相关文章:

javascript - 如何启用谷歌浏览器 chrome ://flags/values using javascript?

html - 链接之间的制表符会导致 Chrome 中的伪元素出现问题

macos - 使用 MMAP 读取时 OS X 上的页面错误

python - 内存错误的可能性?

javascript - 如何确保javascript单页应用程序仅在单个浏览器选项卡上执行

php - 表单替换为文本区域不会给出不同的输出

javascript - 延迟脚本是否在 DOMContentLoaded 事件之前执行?

javascript - 定义将由用户实现的功能

android - 如何在 Android 手机上停止软键盘调整 Chrome 浏览器窗口的大小?

c++ - 超出内存或无效内存引用 - C++ 错误