了解如何使用 Chrome 和开发者工具查找影响页面性能的内存问题,包括 内存泄漏、内存膨胀和频繁的垃圾回收。
摘要
- 使用 Chrome 任务管理器了解您的网页目前使用了多少内存。
- 使用时间轴记录直观呈现一段时间内的内存用量。
- 使用堆快照确定已分离的 DOM 树(内存泄漏的常见原因)。
- 使用分配时间线记录了解新内存在 JS 堆中的分配时间。
概览
本着 RAIL 性能模型的精神,您的性能工作的重点应是 。
内存问题很重要,因为它们通常会被用户察觉。用户可以感知内存 来解决问题:
- 网页的性能会随着时间的推移逐渐变差。这可能是 内存泄漏。内存泄漏是指网页中的错误导致网页越来越多地使用 越来越多
- 网页的效果一直很糟糕。这可能是内存膨胀的症状。内存 “膨胀”是指网页使用的内存超过了达到最佳速度所需的大小。
- 网页性能延迟或似乎经常暂停。这可能是 频繁进行垃圾回收垃圾回收是指浏览器收回内存。浏览器 决定何时发生这种情况。在回收期间,所有脚本执行都会暂停。因此,如果浏览器 经常被当作垃圾收集,脚本执行会频繁暂停
内存膨胀:如何界定“过多”?
内存泄漏很容易定义。如果某个网站使用的内存越来越多 漏了的东西但内存膨胀比较难以界定。什么情况才算是“使用过多内存”?
这里不存在硬性数字,因为不同的设备和浏览器具有不同的功能。 在高端智能手机上流畅运行的同一个网页在低端智能手机上可能会崩溃。
这里的关键是使用 RAIL 模型,并以用户为中心。了解哪些设备最受欢迎 ,然后在这些设备上测试您的网页。如果用户体验始终如一 则该网页可能会超出这些设备的内存容量。
使用 Chrome 任务管理器实时监控内存使用情况
首先,使用 Chrome 任务管理器调查内存问题。任务管理器 是一种实时监控工具,可以告知您页面当前使用的内存量。
按 Shift+Esc 或转到 Chrome 主菜单并选择更多工具 >任务管理器 打开任务管理器。
右键点击任务管理器的表格标题,并启用 JavaScript memory。
这两列可让您从不同方面了解网页使用内存的方式:
- Memory 列表示原生内存。DOM 节点存储在原生内存中。如果 值越来越大,系统会创建 DOM 节点。
- JavaScript Memory 列表示 JS 堆。此列包含两个值。通过 值是实时数字(括号中的数字)。当前使用的电话号码 表示页面上的可到达对象目前使用的内存量。如果此数字为 要么是创建新对象,要么是现有对象在增长。
通过性能记录直观呈现内存泄漏
您还可以使用“性能”面板作为调查的另一个起点。性能 面板可帮助您直观地查看页面在一段时间内的内存使用情况。
- 打开开发者工具上的 Performance 面板。
- 选中内存复选框。
- 录制视频。
为了演示性能内存记录,请考虑使用下面的代码:
var x = [];
function grow() {
for (var i = 0; i < 10000; i++) {
document.body.appendChild(document.createElement('div'));
}
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
每次按下代码中引用的按钮时,系统都会附加一万个 div
节点
附加到文档正文,然后将包含 100 万个 x
字符的字符串推送到 x
数组。
运行此代码会生成类似于以下屏幕截图的时间轴记录:
首先是界面说明。Overview 窗格中的 HEAP 图表(如下所示) NET)表示 JS 堆。概览窗格下方是计数器窗格。在这里,您可以 查看按 JS 堆细分的内存用量(与 Overview 窗格中的 HEAP 图表相同), 文档、DOM 节点、监听器和 GPU 内存。停用某个复选框会在图表中隐藏该复选框。
现在,我们根据屏幕截图来分析代码。如果您看一下节点计数器(
可以看出它与代码完全匹配。节点数量
离散步。您可以假设节点数的每次增加都是对 grow()
的调用。JS
堆图(蓝色图)就不那么简单明了。根据最佳做法,
实际上是强制垃圾回收(通过按下 collect garbage 按钮实现)。如
在录制过程中,您可以看到 JS 堆大小激增。这是正常现象,也是意料之中的:
JavaScript 代码会在每次点击按钮时创建 DOM 节点,
用于创建由 100 万个字符组成的字符串。这里的关键在于,JS 堆
高于开始日期(这里的“开头”是指强制垃圾回收之后的时间点)。在
在现实世界中,如果您看到这种增加 JS 堆大小或节点大小的模式,
可能意味着内存泄漏
使用堆快照发现已分离的 DOM 树内存泄漏
只有当页面或页面的 DOM 节点中没有引用节点时, DOM 树或 JavaScript 代码。我们把节点称为“已分离”从 DOM 树中移除 但有些 JavaScript 仍会引用它。已分离的 DOM 节点是内存泄漏的常见原因。这个 部分介绍了如何使用开发者工具堆性能分析器,用于识别已分离的节点。
下面是一个已分离 DOM 节点的简单示例。
var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);
点击代码中引用的按钮将创建一个包含 10 个 li
子节点的 ul
节点。这些节点
被代码引用,但不存在于 DOM 树中,因此它们已分离。
堆快照是识别已分离的节点的一种方式。顾名思义,堆快照会显示 在事件发生时, 快照。
要创建快照,请打开开发者工具并转到 Memory 面板,然后选择 Heap 快照单选按钮,然后按截取快照按钮。
系统可能需要一些时间来处理和加载快照。完成后,从左侧进行选择 面板(名为 HEAP SNAPSHOTS)。
在 Class filter 文本框中输入 Detached
以搜索已分离的 DOM 树。
展开三角符号以调查分离的树。
以黄色突出显示的节点具有 JavaScript 代码中对它们的直接引用。突出显示的节点 红色的图标没有直接引用。只是因为它们属于黄色节点 树。一般来说,您需要关注黄色节点。更正代码,确保不会出现黄色节点 而且生存时间也会超过所需的时间 黄色节点的树。
点击黄色节点进行进一步调查。在对象窗格中,您可以看到更多
与引用它的代码相关的信息。例如,在下面的屏幕截图中,您可以看到
detachedTree
变量正在引用该节点。要解决这种特定的内存泄漏问题
系统会研究使用 detachedTree
的代码,并确保移除对节点的引用
。
使用分配时间轴识别 JS 堆内存泄漏
分配时间轴是另一个可以帮助您跟踪 JS 堆中的内存泄漏的工具。
为了显示分配时间轴,请考虑使用以下代码:
var x = [];
function grow() {
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);
每次按下代码中引用的按钮时,都会产生一个由 100 万个字符组成的字符串
已添加至 x
数组。
要记录分配时间轴,请打开开发者工具,转到 Profiles 面板,然后选择 Record
分配时间轴单选按钮,按启动按钮,执行您怀疑的操作
然后按停止录制按钮
()
这样就大功告成了。
记录时,请注意分配时间轴上是否显示任何蓝色条,例如在 屏幕截图。
这些蓝色竖线表示新的内存分配。这些新的内存分配 内存泄漏。您可以缩放条形,以过滤 Constructor 窗格以仅显示 在指定的时间范围内分配的
展开该对象并点击它的值,在对象窗格中查看其更多详细信息。对于
例如,在下面的屏幕截图中,通过查看新分配对象的详细信息,
您可以看到,它已分配给 Window
范围内的 x
变量。
按函数调查内存分配情况
您可以使用 Memory 面板中的 Allocation Sampling 类型来查看 JavaScript 函数的内存分配。
- 选中 Allocation Sampling 单选按钮。如果网页上有工作器, 可以使用 Start 按钮旁边的下拉菜单将其选作性能分析目标。
- 按 Start 按钮。
- 在您想调查的网页上执行操作。
- 完成所有操作后,按停止按钮。
开发者工具会按函数显示内存分配明细。默认视图为主要(底部) Up):在顶部显示分配了最多内存的函数。
发现频繁的垃圾回收
如果您的网页经常暂停,则可能存在垃圾回收问题。
您可以使用 Chrome 任务管理器或时间轴内存记录来发现频繁出现的垃圾文件。 。在任务管理器中,Memory 或 JavaScript Memory 经常出现上升和下降 值表示频繁的垃圾回收。在时间轴记录中,频繁上升和下降 JS 堆或节点计数图表表示垃圾回收频繁。
确定问题后,您可以使用分配时间线记录来找出 以及是哪些函数导致了分配。