支配者视图¶
支配者视图是 Firefox 46 中的新功能。
从 Firefox 46 开始,内存工具包含一个名为支配者视图的新视图。这对于理解您的网站分配的对象的“保留大小”很有用:即对象本身的大小加上它们通过引用保持活动状态的对象的大小。
如果您已经了解浅层大小、保留大小和支配者是什么,请跳到支配者 UI 部分。否则,您可能需要回顾有关 支配者概念 的文章。
支配者 UI¶
要查看快照的支配者视图,请在“视图”下拉列表中选择“支配者”。它看起来像这样
支配者视图由两个面板组成
支配者树面板¶
支配者树告诉您快照中的哪些对象保留了最多的内存。
在 UI 的主要部分,第一行标记为“GC 根”。紧随其后的是
每个 GC 根节点的条目。在 Gecko 中,存在多个内存图,因此存在多个根。可能存在许多(通常是临时的)根。例如:分配在堆栈上的变量需要被根化,或者内部缓存可能需要根化其元素。
任何其他从两个不同根引用的节点(因为在这种情况下,没有一个根支配它)。
每个条目显示
节点的保留大小,以字节和总大小的百分比表示
节点的浅层大小,以字节和总大小的百分比表示
节点的名称和内存中的地址。
条目按其保留的内存量排序。例如
在此屏幕截图中,我们可以在“GC 根”下看到五个条目。前两个是 Call 和 Window 对象,分别保留了内存快照总大小的大约 21% 和 8%。您还可以看到这些对象的“浅层大小”相对较小,因此几乎所有保留的大小都位于它们支配的对象中。
在每个 GC 根的正下方,您将看到所有此根是 直接支配者 的节点。这些节点也按其保留大小排序。
例如,如果我们点击第一个 Window 对象
我们可以看到此 Window 支配一个 CSS2Properties 对象,其保留大小为快照总大小的 2%。同样,浅层大小非常小:几乎所有其保留大小都位于其支配的节点中。通过单击 Function 旁边的展开箭头,我们可以看到这些节点。
通过这种方式,您可以快速了解快照中哪些对象保留了最多的内存。
您可以使用 Alt + 单击 展开节点下的整个图形。
调用栈¶
在工具顶部的工具栏中有一个名为“按标签”的下拉菜单
默认情况下,此设置为“类型”。但是,您可以将其设置为“调用栈”以查看代码中分配对象的准确位置。
注意
此选项在 Firefox 46 中称为“分配栈”。
要启用此功能,您必须在运行分配对象的代码之前选中标记为“记录调用栈”的复选框。然后拍摄快照,然后在“按标签”下拉菜单中选择“调用栈”。
现在节点的名称将包含分配它的函数的名称,以及函数分配它的确切位置的文件、行号和字符位置。单击文件名将带您到调试器中的该位置。
注意
有时您会在这里看到“(不可用栈)”。特别是,当前仅为对象记录分配栈,而不是数组、字符串或内部结构。
保留路径面板¶
保留路径面板是 Firefox 47 中的新功能。
保留路径面板向您显示,对于给定节点,从该节点到 GC 根的 5 条最短路径。这使您能够查看所有阻止给定节点被垃圾回收的节点。如果您怀疑某个对象正在泄漏,这将向您准确显示哪些对象持有对它的引用。
要查看节点的保留路径,您必须在支配者树面板中选择该节点
在这里,我们选择了一个对象,并且可以看到一条返回到 GC 根的路径。
Window
GC 根持有对 HTMLDivElement
对象的引用,该对象持有对 Object
的引用,依此类推。如果您查看支配者树面板,您可以在那里跟踪相同的路径。如果删除了这些引用中的任何一个,则它们下面的项目可以被垃圾回收。
图中的每个连接都用引用对象的变量名标记。
有时从节点返回的保留路径不止一条
这里有三条从 DocumentPrototype
节点到 GC 根的路径。如果删除其中一条,则 DocumentPrototype
仍然不会被垃圾回收,因为它仍然由其他两条路径保留。
示例¶
让我们看看一些简单的代码如何在支配者视图中反映。
我们将使用 怪物分配示例,它创建三个数组,每个数组包含 5000 个怪物,每个怪物都有一个随机生成的名称。
拍摄快照¶
要查看它在支配者视图中的样子
加载页面
在 设置 中启用内存工具(如果您尚未启用)。
打开内存工具
选中“记录调用栈”
按标记为“生成怪物!”的按钮
拍摄快照
切换到“支配者”视图
分析支配者树¶
您会看到这三个数组作为前三个 GC 根,每个数组保留了大约 23% 的总内存使用量
如果展开数组,您将看到它包含的对象(怪物)。每个怪物的浅层大小都相对较小,为 160 字节。这包括整数眼数和触手数。每个怪物都有更大的保留大小,这由用于怪物名称的字符串来解释
所有这些都与我们期望看到的 内存图 密切相关。但是,您可能想知道:保留所有三个数组的顶级对象在哪里?如果我们查看其中一个数组的保留路径面板,我们将看到它
在这里,我们可以看到保留对象,甚至可以看到此特定数组是 fierce
怪物的数组。但是数组也直接根化,因此如果对象停止引用数组,它仍然没有资格进行垃圾回收。
这意味着对象不支配数组,因此不会显示在支配者树视图中。请参阅支配者概念文章的相关部分。
使用调用栈视图¶
最后,您可以切换到调用栈视图,查看对象在何处分配,并跳转到调试器中的该点。