支配者视图¶
支配者视图是 Firefox 46 中的新功能。
从 Firefox 46 开始,内存工具包含一个名为“支配者视图”的新视图。这对于理解您的网站分配的对象的“保留大小”很有用:即对象本身的大小加上它们通过引用保持存活的对象的大小。
如果您已经了解浅层大小、保留大小和支配者是什么,请跳到支配者 UI 部分。否则,您可能需要查看有关支配者概念的文章。
支配者 UI¶
要查看快照的支配者视图,请在“视图”下拉列表中选择“支配者”。它看起来像这样
支配者视图由两个面板组成
支配者树面板¶
支配者树告诉您快照中的哪些对象保留了最多的内存。
在 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}¶
最后,您可以切换到调用堆栈视图,查看对象在何处分配,并跳转到调试器中的该点