内存检查器简介

Kim-Anh Tran
Kim-Anh Tran

本文介绍了已在 Chrome 91 中发布的内存检查器。您可以使用它检查 ArrayBuffer、TypedArray、DataView 和 Wasm 内存。

简介

您是否曾想了解 ArrayBuffer 中的数据?在内存检查器出现之前,开发者工具只能对 ArrayBuffer 进行有限的分析。在调试会话期间,通过 Scope 视图进行检查仅限于查看数组缓冲区中的单个值列表,这使得难以理解数据的整体含义。例如,在以下示例中,范围视图会将缓冲区显示为可展开的数组范围:

开发者工具中的范围视图

导航到缓冲区内的特定范围是一项痛点,需要用户向下滚动才能最终找到该索引。不过,即使导航到某个位置很容易,实际检查值的方式也非常繁琐:很难看出这些数字的含义。尤其是,如果它们不应被解读为单个字节,而应被解读为 32 位整数,该怎么办?

使用内存检查器检查值

内存检查器

在 Chrome 91 中,我们引入了内存检查器,这是一种用于检查数组缓冲区的工具。您可能之前见过用于查看二进制数据的内存检查工具,这些工具会以网格形式显示二进制内容及其地址,并提供不同的方式来解读底层值。这就是 Memory Inspector 为您带来的功能。借助内存检查器,您现在可以查看内容、浏览内容,以及选择用于解读当前值的类型。它会直接在字节旁边显示 ASCII 值,并允许用户选择不同的字节序。请参阅下方内存检查器的实际运作方式:

想试用一下吗?如需了解如何打开 Memory Inspector 并查看数组缓冲区(或 TypedArray、DataView 或 Wasm 内存),以及有关如何使用它的更多信息,请参阅我们的 Memory Inspector 文档。不妨试试这些玩具示例(适用于 JS、Wasm 和 C++)。

设计内存检查器

在本部分中,我们将了解 Memory Inspector 是如何使用 Web 组件设计的,并介绍我们的一个设计目标及其实现方式。如果您有兴趣了解更多信息,请参阅内存检查器的设计文档

您可能看过我们关于迁移到 Web 组件的博文,其中 Jack 发布了我们的内部指南,介绍了如何使用 Web 组件构建界面组件。向 Web 组件迁移与我们在 Memory Inspector 上的工作同时进行,因此我们决定试用新系统。下图显示了我们构建的用于创建内存检查器的组件(请注意,在内部我们将其称为线性内存检查器):

Web 组件

LinearMemoryInspector 组件是父级组件,用于组合构建内存检查器中所有元素的子组件。它基本上接受 Uint8Arrayaddress,并且在任一项发生更改时,都会将数据传播到其子项,从而触发重新渲染。LinearMemoryInspector 本身会呈现三个子组件:

  1. LinearMemoryViewer(显示值),
  2. LinearMemoryNavigator(允许导航),以及
  3. LinearMemoryValueInterpreter(显示对底层数据的不同类型解读)。

后者本身就是一个父级组件,用于呈现 ValueInterpreterDisplay(显示值)和 ValueInterpreterSettings(选择要在显示屏中看到的类型)。

每个组件都旨在仅表示界面的一个小组件,以便在需要时重复使用组件。每当在组件上设置新数据时,系统都会触发重新渲染,以显示在组件上设置的数据的反映性更改。以下示例展示了使用我们组件的工作流程,其中用户正在更改地址栏中的地址,这会通过设置新数据(在本例中为要查看的地址)触发更新:

组件图

LinearMemoryInspector 会将自己添加为 LinearMemoryNavigator 的监听器。addressChanged 函数将在 address-changed 事件发生时触发。现在,只要用户修改地址输入,系统就会发送上述事件,以便调用 addressChanged 函数。此函数现在会在内部保存地址,并使用 data(address, ..) Setter 更新其子组件。子组件会在内部保存地址并重新渲染其视图,以显示该特定地址的内容。

设计目标:使性能和内存用量不受缓冲区大小的影响

在设计内存检查器时,我们考虑的一个方面是,内存检查器的性能应与缓冲区大小无关。

如您在前面部分所见,LinearMemoryInspector 组件接受 UInt8Array 以呈现值。同时,我们还希望确保内存检查器无需保留全部数据,因为内存检查器只会显示其中的一部分(例如,Wasm 内存可以达到 4GB,而我们不希望在内存检查器中存储 4GB)。

因此,为了确保内存检查器的速度和内存用量不受我们显示的实际缓冲区的影响,我们让 LinearMemoryInspector 组件仅保留原始缓冲区的子范围

为了实现这一点,LinearMemoryInspector 首先需要再接受两个参数:一个 memoryOffset 和一个 outerMemoryLengthmemoryOffset 表示传递的 Uint8Array 的起始偏移量,必须提供此偏移量才能呈现正确的数据地址。outerMemoryLength 是原始缓冲区的长度,必须了解此长度才能了解我们可以显示的范围:

缓存空间

有了这些信息,我们就可以确保在不实际拥有所有数据的情况下,仍能呈现与之前相同的视图(address 周围的内容)。如果客户请求的地址属于其他范围,该怎么办?在这种情况下,LinearMemoryInspector 会触发 RequestMemoryEvent,后者会更新要保留的当前范围;如下所示:

事件触发器流程图

在此示例中,用户浏览内存页面(Memory Inspector 使用分页来显示数据块),这会触发 PageNavigationEvent,而 PageNavigationEvent 本身会触发 RequestMemoryEvent。该事件会启动提取新范围的操作,然后通过设置数据将其传播到 LinearMemoryInspector 组件。因此,我们会显示新提取的数据。

您知道吗?您甚至可以检查 Wasm 和 C/C++ 代码中的内存

内存检查器不仅适用于 JavaScript 中的 ArrayBuffers,还可用于检查 Wasm 内存以及 C/C++ 引用/指针指向的内存(使用我们的 DWARF 扩展程序 - 如果您尚未尝试,不妨试试!请参阅此处介绍如何使用新式工具调试 WebAssembly。下面简要介绍了 Memory Inspector 在 Web 上对 C++ 进行原生调试时的运作方式:

在 C++ 中检查内存

总结

本文介绍了 Memory Inspector,并简要介绍了其设计。我们希望内存检查器能帮助您了解 ArrayBuffer 中发生的情况 :-)。如果您有改进建议,欢迎告诉我们并提交 bug

下载预览渠道

不妨考虑将 Chrome Canary 版开发者版Beta 版用作默认开发浏览器。通过这些预览渠道,您可以使用最新的 DevTools 功能、测试尖端的 Web 平台 API,并在用户发现问题之前发现您网站上的问题!

与 Chrome 开发者工具团队联系

您可以使用以下选项讨论与 DevTools 相关的新功能、更新或任何其他内容。