内存术语

内存 工具中 使用以下术语,用于调查内存问题。 这些内存术语通常适用于内存分析,以及适用于 Java 或 .NET 等语言的内存分析工具。

若要详细了解如何使用 内存 工具,请参阅 使用内存工具记录堆快照

内存图

将网页使用的内存视为图形:一个包含通过边缘连接在一起的节点的结构

内存的可视表示形式

内存图中的节点表示页面使用的对象,包括基元类型(如 JavaScript 数字或字符串)以及关联数组等对象。 内存图中的节点和边缘具有以下标签:

  • (对象) 的节点使用用于生成它们的 构造函数 的名称进行标记。

  • 边缘 使用 属性名称进行标记。

图中的节点可以通过两种方式保存内存:

  • 直接;内存由对象本身持有。

  • 隐式,通过保留对其他对象的引用。 包含对其他对象的引用的对象可防止垃圾回收 (GC) 自动释放这些对象。

JavaScript 堆和呈现器内存

JavaScript 堆是浏览器进程中所有 JavaScript 和 WebAssembly 对象的内存区域。 JavaScript 堆在支持 Microsoft Edge) 的 V8 JavaScript 引擎之后也称为 V8 内存 (。

JavaScript 堆是呈现器内存的一部分。 呈现器内存是呈现网页的浏览器进程使用的内存。 呈现器内存由以下各项组成:

  • 本机内存,例如表示 DOM 节点的 C++ 对象使用的内存。
  • 页面的 JavaScript 堆内存。
  • 页面启动的所有专用辅助角色的 JavaScript 堆内存。

内存工具显示两者:

  • V8 内存。
  • 在本机内存中分配的与呈现的网页相关的对象。

垃圾回收根

当从浏览器的本机代码引用 V8 虚拟机外部的 JavaScript 对象时,浏览器会创建垃圾回收根 (GC 根) 。 这些引用称为 句柄

有许多内部 GC 根,其中大多数对 Web 开发人员来说并不感兴趣。 从网页的角度来看,存在以下类型的 GC 根:

  • 每个 iframe) 中 (一个窗口全局对象。

  • 有时,对象由 控制台 工具设置的调试上下文保留,例如在 控制台 工具中计算 JavaScript 表达式时。 若要从内存工具中删除这些对象,在录制堆快照之前,请清除“控制台”工具并在“源”工具中停用断点。

内存图以 GC 根开头,该根可能是 window 浏览器的对象或 Global Node.js 模块的对象。 你无法控制根对象的垃圾回收方式:

无法控制根对象的垃圾回收方式

无法从根目录访问的节点可以进行垃圾回收。

对象大小和距离

使用 内存 工具时,你可能会发现自己正在查看以下信息列:

  • 距离
  • 浅层大小
  • 保留大小

内存工具中的“距离”、“浅层大小”和“保留大小”列

浅表大小保留大小列中的数字是字节数。

距离

JavaScript 堆中对象的 距离 是对象与 GC 根之间的最短路径上的节点数。 距离越短,此对象在网页的内存使用中扮演重要角色的可能性就越大。

浅层大小

浅层大小是对象直接持有的 JavaScript 堆的大小。 对象的浅表大小通常很小,因为 JavaScript 对象通常只将对象的描述(而不是值)存储在对象的直接保留内存中。 大多数 JavaScript 对象将其值存储在 JavaScript 堆中其他位置的 后备存储 中,并且仅在该对象直接拥有的 JavaScript 堆部分公开一个小包装器对象。

可以将 “内存 ”工具配置为报告对象的总内存大小,而不是仅报告它们直接保留的内存大小。 若要了解详细信息,请参阅配置浅表大小列,以使用内存工具在记录堆快照中包含整个对象的大小。

但是,即使一个小对象也可以 间接保存大量内存,因为垃圾回收进程会阻止其他对象被释放。

保留的大小

保留大小是对象隐式持有的内存大小,在删除对象和其他现有保留器以及从 GC 根无法访问的所有依赖对象后,可以释放该大小。

也就是说,对象的保留大小是从内存图中删除对象及其所有依赖对象时将重新获取的内存量。

保留的大小不能小于浅层大小。

当某个对象由多个节点保留时,该对象的大小将显示在具有 GC 根最短路径的保留器节点的保留大小中。

固定器

对象的 保留器 是保存对该对象的引用的其他对象。 “内存”工具的“保留器”部分显示保存对“摘要”视图中所选对象的引用的对象。

默认情况下,内存工具的“保留器”部分按距离排序,这意味着首先显示对象的最简单的保留路径。

浏览器的垃圾回收器可以丢弃任何没有保留器的对象,这可以减少内存使用量。

V8 细节

分析内存时,了解堆快照为何以某种方式显示会很有帮助。 本部分介绍 V8 JavaScript 虚拟机 如何将某些对象存储在内存中, (此处缩写为 V8 VM,或者仅 VM) ,这有助于在 内存 工具中分析堆快照。

JavaScript 基元

在 JavaScript 中,有多种基元类型,例如:

  • 数字 (,例如 3.14159) 。
  • 布尔值 (truefalse) 。
  • 字符串 (,例如 "Werner Heisenberg") 。

基元不能引用其他值,并且始终是叶节点 (在内存图中也称为 终止节点) 。

数字 可以存储为:

  • 称为小整数的即时 31 位 整数 值 (SMIs) 。

  • 堆对象,称为 堆数。 堆数用于存储不适合小整数 (SMI) 形式的值,例如 类型的 double值,或者当值需要装箱时(例如设置其属性)。

字符串 可以存储在以下任一中:

  • VM 堆

  • 呈现器内存的外部。 创建 包装器对象 并将其用于访问外部存储,例如,从 Web 接收的脚本源和其他内容被存储,而不是复制到 VM 堆。

JavaScript 对象

新 JavaScript 对象的内存是从专用 JavaScript 堆 (或 VM 堆) 分配的。 这些对象由 V8 VM 的垃圾回收器管理,因此,只要至少有一个对它们的引用,这些对象就保持活动状态。

其他对象

  • 本机对象:未存储在 JavaScript 堆中的任何内容称为 本机对象。 与堆对象相比,本机对象在其整个生存期内不受 V8 垃圾回收器管理,并且只能通过使用 JavaScript 包装器对象从 JavaScript 访问。

  • 串联字符串:由于 JavaScript 中的字符串串联,存储然后联接在一起的字符串在 V8 中存储为 串联字符串 。 字符串内容的联接仅根据需要进行,例如需要构造联接字符串的子字符串时。

    例如,如果连接 ab,则会收到表示串联结果的串联字符串 (a, b) 。 如果稍后与该结果连接 c ,则会收到另一个串联字符串: ((a, b), c)

  • 数组数组 是具有数字键的对象。 数组在 V8 VM 中广泛使用,用于存储大量数据。 用作字典的键值对集作为数组实现。

    典型的 JavaScript 对象仅存储为以下两种数组类型之一:

    • 用于存储命名属性的数组。
    • 用于存储数值元素的数组。

    当存在少量属性时,这些属性存储在 JavaScript 对象内部。

  • system/Map:一个对象,用于描述它的对象类型和布局。 例如, 系统/映射 对象用于描述隐式对象层次结构,以便快速访问属性。 请参阅 V8 中的 Fast 属性

注意

此页面的部分内容是基于 Google 创建和 共享 的工作进行的修改,并根据 Creative Commons 署名 4.0 国际许可中所述的条款使用。 原始页面 在此处 找到,由 Meggin Kearney (Technical Writer) 创作。

Creative Commons 许可证 此作品根据 Creative Commons 署名 4.0 国际许可获得许可