支配者视图

支配者视图是 Firefox 46 中的新功能。

从 Firefox 46 开始,内存工具包含一个名为“支配者视图”的新视图。这对于理解您的网站分配的对象的“保留大小”很有用:即对象本身的大小加上它们通过引用保持存活的对象的大小。

如果您已经了解浅层大小、保留大小和支配者是什么,请跳到支配者 UI 部分。否则,您可能需要查看有关支配者概念的文章。

支配者 UI

要查看快照的支配者视图,请在“视图”下拉列表中选择“支配者”。它看起来像这样

支配者视图由两个面板组成

  • the 支配者树面板 显示快照中的哪些节点保留了最多的内存

  • the 保留路径面板 (Firefox 47 中的新功能) 显示单个节点的 5 条最短保留路径。

支配者树面板

支配者树告诉您快照中的哪些对象保留了最多的内存。

在 UI 的主体部分,第一行标有“GC 根”。紧随其后的是

  • 每个 GC 根节点。在 Gecko 中,存在多个内存图,因此存在多个根。可能存在许多(通常是临时的)根。例如:分配在堆栈上的变量需要被根化,或者内部缓存可能需要根化其元素。

  • 任何其他从两个不同根引用的节点(因为在这种情况下,这两个根都不支配它)。

每个条目显示

  • 节点的保留大小,以字节和总大小的百分比表示

  • 节点的浅层大小,以字节和总大小的百分比表示

  • 节点的名称和内存中的地址。

条目按其保留的内存量排序。例如

在此屏幕截图中,我们可以在“GC 根”下看到五个条目。前两个是 Call 和 Window 对象,分别保留了内存快照总大小的大约 21% 和 8%。您还可以看到这些对象的“浅层大小”相对较小,因此几乎所有保留大小都在它们支配的对象中。

在每个 GC 根的正下方,您将看到所有此根是直接支配者的节点。这些节点也按其保留大小排序。

例如,如果我们点击第一个 Window 对象

我们可以看到此 Window 支配一个 CSS2Properties 对象,其保留大小为快照总大小的 2%。同样,浅层大小非常小:几乎所有其保留大小都在其支配的节点中。通过点击 Function 旁边的展开箭头,我们可以看到这些节点。

这样,您可以快速了解快照中哪些对象保留了最多的内存。

您可以使用 [Alt]{.kbd} + 点击展开节点下的整个图形。

调用堆栈 {#Call_Stack}

在工具顶部的工具栏中有一个名为“按以下标签”的下拉菜单

默认情况下,此设置为“类型”。但是,您可以将其设置为“调用堆栈”,以查看代码中对象的确切分配位置。

::: {.note} 此选项在 Firefox 46 中称为“分配堆栈”。 ::

要启用此功能,您必须在运行分配对象的代码之前选中“记录调用堆栈”复选框。然后拍摄快照,然后在“按以下标签”下拉菜单中选择“调用堆栈”。

现在,节点的名称将包含分配它的函数的名称,以及函数分配它的确切位置的文件、行号和字符位置。点击文件名将带您到调试器中的该位置。

::: 有时您会在这里看到“(没有可用堆栈)”。特别是,目前仅为对象记录分配堆栈,而不记录数组、字符串或内部结构。 ::

保留路径面板

::: {.geckoVersionNote} 保留路径面板是 Firefox 47 中的新功能。 ::

保留路径面板显示给定节点到 GC 根的 5 条最短路径。这使您能够查看所有阻止给定节点被垃圾回收的节点。如果您怀疑某个对象正在泄漏,这将向您准确显示哪些对象持有对它的引用。

要查看节点的保留路径,您必须在支配者树面板中选择该节点

在这里,我们选择了一个对象,并且可以看到一条返回到 GC 根的路径。

The Window GC 根持有对 HTMLDivElement 对象的引用,该对象持有对 Object 的引用,依此类推。如果您查看支配者树面板,您可以在那里跟踪相同的路径。如果删除了这些引用中的任何一个,则其下面的项目可以被垃圾回收。

图中的每个连接都用引用的对象的变量名称标记。

有时从节点返回的保留路径不止一条

这里有从 DocumentPrototype 节点到 GC 根的三条路径。如果删除其中一条,则 DocumentPrototype 仍然不会被垃圾回收,因为它仍然由其他两条路径保留。

示例 {#Example}

让我们看看一些简单的代码如何在支配者视图中反映。

我们将使用怪物分配示例,它创建三个数组,每个数组包含 5000 个怪物,每个怪物都有一个随机生成的名称。

拍摄快照

要查看它在支配者视图中的样子

  • 加载页面

  • 设置中启用内存工具(如果您尚未启用)。

  • 打开内存工具

  • 选中“记录调用堆栈”

  • 按下标有“生成怪物!”的按钮

  • 拍摄快照

  • 切换到“支配者”视图

分析支配者树

您将看到这三个数组作为前三个 GC 根,每个数组保留了大约 23% 的总内存使用量

如果您展开一个数组,您将看到它包含的对象(怪物)。每个怪物都有一个相对较小的 160 字节的浅层大小。这包括整数眼睛和触手计数。每个怪物都有一个更大的保留大小,这是由用于怪物名称的字符串解释的

所有这些都与我们期望看到的内存图紧密匹配。但是,您可能想知道:保留所有三个数组的顶级对象在哪里?如果我们查看其中一个数组的保留路径面板,我们将看到它

在这里,我们可以看到保留对象,甚至看到此特定数组是 fierce 怪物的数组。但是该数组也被直接根化,因此如果该对象停止引用该数组,它仍然不符合垃圾回收的条件。

这意味着该对象不支配该数组,因此未显示在支配者树视图中。请参阅支配者概念文章的相关部分

使用调用堆栈视图 {#Using_the_Call_Stack_view}

最后,您可以切换到调用堆栈视图,查看对象在何处分配,并跳转到调试器中的该点