参考文章:
https://learn.microsoft.com/zh-cn/microsoft-edge/devtools-guide-chromium/memory-problems/heap-snapshots
https://www.cnblogs.com/chinasoft/p/18530011
https://www.jianshu.com/p/cc991f3217df
有些3D页面,需要7*24小时运行,但是经常容易出现OOM问题,故探索解决。
术语介绍
下面介绍了这些列。
距离
JavaScript 堆中对象的 距离 是对象与 GC 根之间的最短路径上的节点数。 距离越短,此对象在网页的内存使用中扮演重要角色的可能性就越大。
浅层大小
浅层大小是对象直接持有的 JavaScript 堆的大小。 对象的浅表大小通常很小,因为 JavaScript 对象通常只将对象的描述(而不是值)存储在对象的直接保留内存中。 大多数 JavaScript 对象将其值存储在 JavaScript 堆中其他位置的 后备存储 中,并且仅在该对象直接拥有的 JavaScript 堆部分公开一个小包装器对象。
但是,即使一个小对象也可以 间接保存大量内存,因为垃圾回收进程会阻止其他对象被释放。
浅层大小列中的数字是字节数。
保留的大小
保留大小是对象隐式持有的内存大小,在删除对象和其他现有保留器以及从 GC 根无法访问的所有依赖对象后,可以释放该大小。
也就是说,对象的保留大小是从内存图中删除对象及其所有依赖对象时将重新获取的内存量。
保留的大小不能小于浅层大小。
当某个对象由多个节点保留时,该对象的大小将显示在具有 GC 根最短路径的保留器节点的保留大小中。
“保留的大小”列中的数字是字节数。
固定器
对象的 保留器 是保存对该对象的引用的其他对象。 “内存”工具的“保留器”部分显示保存对“摘要”视图中所选对象的引用的对象。
默认情况下,内存工具的“保留器”部分按距离排序,这意味着首先显示对象的最简单的保留路径。
浏览器的垃圾回收器可以丢弃任何没有保留器的对象,这可以减少内存使用量。
V8 细节
分析内存时,了解堆快照为何以某种方式显示会很有帮助。 本部分介绍 V8 JavaScript 虚拟机 如何将某些对象存储在内存中, (此处缩写为 V8 VM,或者仅 VM) ,这有助于在 内存 工具中分析堆快照。
JavaScript 基元
在 JavaScript 中,有多种基元类型,例如:
- 数字 (,例如
3.14159
) 。 - 布尔值 (
true
或false
) 。 - 字符串 (,例如
"Werner Heisenberg"
) 。
基元不能引用其他值,并且始终是叶节点 (在内存图中也称为 终止节点) 。
数字 可以存储为:
- 称为小整数的即时 31 位 整数 值 (SMIs) 。
- 堆对象,称为 堆数。 堆数用于存储不适合小整数 (SMI) 形式的值,例如 类型的
double
值,或者当值需要装箱时(例如设置其属性)。
字符串 可以存储在以下任一中:
- VM 堆。
- 在 呈现器内存的外部。 创建 包装器对象 并将其用于访问外部存储,例如,从 Web 接收的脚本源和其他内容被存储,而不是复制到 VM 堆。
JavaScript 对象
新 JavaScript 对象的内存是从专用 JavaScript 堆 (或 VM 堆) 分配的。 这些对象由 V8 VM 的垃圾回收器管理,因此,只要至少有一个对它们的引用,这些对象就保持活动状态。
其他对象
- 本机对象:未存储在 JavaScript 堆中的任何内容称为 本机对象。 与堆对象相比,本机对象在其整个生存期内不受 V8 垃圾回收器管理,并且只能通过使用 JavaScript 包装器对象从 JavaScript 访问。
- 串联字符串:由于 JavaScript 中的字符串串联,存储然后联接在一起的字符串在 V8 中存储为 串联字符串 。 字符串内容的联接仅根据需要进行,例如需要构造联接字符串的子字符串时。例如,如果连接
a
和b
,则会收到表示串联结果的串联字符串(a, b)
。 如果稍后与该结果连接c
,则会收到另一个串联字符串:((a, b), c)
。 - 数组: 数组 是具有数字键的对象。 数组在 V8 VM 中广泛使用,用于存储大量数据。 用作字典的键值对集作为数组实现。典型的 JavaScript 对象仅存储为以下两种数组类型之一:
- 用于存储命名属性的数组。
- 用于存储数值元素的数组。
- system/Map:一个对象,用于描述它的对象类型和布局。 例如, 系统/映射 对象用于描述隐式对象层次结构,以便快速访问属性。 请参阅 V8 中的 Fast 属性。