专注于
IT技术和业内交流

Chrome DevTools — 查找常见的内存问题

了解如何使用Chrome DevTools 来查找影响网页性能的问题,包括内存泄漏、 内存膨胀和频繁的垃圾回收等内存问题。

概述

RAIL性能模型中,你的焦点应该放在你的用户身上。

内存问题非常重要,因为它们往往是由用户感知。用户可以通过以下方式感知内存问题︰

  • 网页的性能随着时间的推移越来越差。这种表现很可能是发生了内存泄漏。原因可能是页面中的Bug导致页面随着时间的推移逐步使用更多的内存。

  • 网页的性能一直很差。这种状况可能是因为内存膨胀(memory bloat)。优化内存占用是网页提速的必要条件。

  • 页面经常延迟或卡顿。这种状况可能是频繁的垃圾回收造成的。当浏览器觉得需要回收内存的时候就会执行GC。在执行期间所有的脚本都会暂停。如果GC很频繁,那脚本被暂停的次数也会很频繁。

内存膨胀︰ 多少才是”过多”?

内存泄漏很容易定义。如果一个网站在逐渐使用更多的内存,那就说明你有内存泄漏。但是内存膨胀有点难定义。我们用什么来定义”使用太多的内存”呢?

这是没有准则的,因为不同的设备和浏览器有不同的性能表现。在高端的智能手机顺利运行的同一页上低端智能手机就有可能崩溃。

这里的关键是使用RAIL模型,并专注于您的用户。找出哪些设备是受你用户喜爱的,然后在这些设备上测试你页面的表现。如果表现一直很差,那么说明页面所需内存可能超过了这些设备极限。

用Chrome任务管理器监视内存实时使用

让我们用 Chrome 任务管理器作为内存问题检测的起点。他是一个实时显示器,能告诉你当前页面有多少内存正在使用。

  1. Shift+Esc或转到Chrome主菜单并选择More tools > Task manager,打开任务管理器。

    opening the task
manager

  2. 在任务管理器中右键单击并启用JavaScript memory

    enable javascript
memory

这两列是在用不同角度来说明你网页的内存占用情况︰

  • Memory 列表示本机内存。DOM 节点存储在本机内存中。如果此值增加,就说明创建了新的 DOM 节点。
  • JavaScript Memory 列表示 JS 堆。此列包含两个值。你感兴趣的值是那个活跃的数字 (括号中的数字)。
    该数值表明你页面上的可访问对象占用的总内存。如果此数值正在增加,那就说明有新的对象在创建或者现有对象的大小在在增长。

用 Timeline 录制可视化的内存泄露

在你的检查过程中,你还可以使用Timeline面板作为另一个起点。时间轴面板可帮助您随着时间的推移更直观地显示页面的内存使用。

  1. 在DevTools上打开Timeline面板。
  2. 启用 Memory复选框。
  3. 进行录音

提示︰ 这是一个好的习惯,单击collect garbage按钮 (force garbage collection button)开始或结束您的录制与强制的垃圾回收。

为了演示时间线内存录制,请思考下面的代码︰

    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);

每次按下按钮就会有 1 万个div节点附加到文档的正文中,和一个 100 万个x的字符串被push 入x数组。运行这段代码将产生像下面的屏幕快照的时间线录制︰

simple growth example

首先介绍下用户界面。HEAP视图在(NET 下面)Overview面板内表示JS 堆。
Overview面板下面是Counter面板。在这里你可以看到 JS 堆(和Overview面板中一样),documents、 DOM 节点、 侦听器和 GPU 内存的使用情况。禁用复选框可以从面板中隐藏某项。

现在,分析快照代码。你可以看到节点计数器(绿色曲线)的增长是很规律的按照步骤一步步增长的。
你可以认为每增加一个节点计数器就会调用grow()
JS 堆图 (蓝色曲线) 就不是那么简单了。
比较推荐的做法是,以首次下降点即强制执行GC点 (按collect garbage按钮时)作为记录的开始,你可以看到 JS 堆的曲线呈穗状。
这是符合预期的因为 JavaScript 代码在创建包含100万长度字符串的DOM 节点时做了大量工作。
最关键的一点是,JS 堆结束时比起始点 (被强制GC的点) 高。
在真实情况下,如果你看到这种节点与JS堆图的增长模式,它可能意味着你的页面有内存泄漏。

用快照检查 DOM 树内存泄漏

一个 DOM 节点只能在对它没有任何从页面的 DOM 树或 JavaScript 代码的引用时才能被回收。
当一个节点从 DOM 树中删除, JavaScript 却还在引用它,我们把这种情况叫做detached
detached 节点是内存泄漏的常见原因。这一节教你如何使用 DevTools 的堆探查器来识别detached节点。

这里是一个detached 节点的简单例子。


var detachedNodes; 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);

单击按钮创建一个ul节点与十个li子节点。这些节点由代码引用,但不存在 DOM 树中。这就叫detached(分离节点)

堆快照是一种用来标识分离节点的方法。顾名思义,堆快照向您展示您的页面在何时又如何将内存分配给 JS 对象和 DOM 节点的。

若要创建快照,请打开 DevTools,转到Profiles面板中,选择Take Heap Snapshot单选按钮,然后按Take Snapshot按钮。

take heap snapshot

快照可能需要一些时间去分析与加载。一旦完成,您将在左侧面板 (名称为 HEAP SNAPSHOTS) 中找到他。

Class filter文本框中搜索Detached类型的分离DOM 树。

filtering for detached nodes

展开分离树,查看详情

investigating detached tree

黄色突出显示的节点说明 JavaScript 代码对他们是直接引用的。而红色表示没有直接引用。
他们依然存在与内存中因为他们是黄色节点树的一部分。
一般情况下,你应该把重点放在黄色的节点。修复您的代码,确保你不再需要他们的时候他们不再活跃,当然同样要确保红色的节点存在的周期不会比黄色的更久。

单击黄色的节点,以作进一步检查。在对象窗格中您可以看到有关引用它的代码的详细信息。
例如,在下面的截图中你可以看到detachedTree变量的引用节点。
若要修复此内存泄漏,将研究使用此detachedTree的代码,并确保当不再需要它时移除对该节点的引用。

investigating a yellow node

用 Allocation Timeline 查找 JS 内存泄漏

Timeline是另一个可以帮助您跟踪您的 JS 堆中内存泄漏的工具。

为了演示时间线内存录制,请思考下面的代码︰


var x = []; function grow() { x.push(new Array(1000000).join('x')); } document.getElementById('grow').addEventListener('click', grow);

在代码中引入如下代码,每次执行都将有100万长的字符串被推入 x 数组。

要录制Allocation Timeline、 打开 DevTools、 转到Profiles面板,选择Record Allocation Timeline的单选按钮,按下开始按钮,重现怀疑可能导致内存泄漏的动作,然后在按停止录制按钮 (stop recording button)。

在录制时,请注意是否有蓝色条显示在Allocation Timeline,就像下面的截图。

new allocations

这些蓝色代表新的内存分配。这些分配很可能就是内存泄漏点。你可以在Constructor窗格中进行缩放操作以便筛选显示指定时间范围内的分配对象。

zoomed allocation timeline

Object面板中,点击想要查看的对象,展开以查看更多详细信息。例如,下面的屏幕截图,通过查看新分配对象的详细信息,你将能够看到x变量在Window范围内。

object details

发现频繁的垃圾回收

如果您的网页经常出现卡顿状态,很可能你的网页有垃圾收集的问题。

您可以使用任一Chrome任务管理器或时间线内存录制去发现频繁的垃圾回收。
在任务管理器中,MemoryJavaScript Memory值频繁地上升和下降代表垃圾回收频繁。在时间线录制时, JS 堆或节点计数图频繁地上升和下降表明垃圾回收频繁。

一旦你已经发现了问题,你就可以使用Timeline找出分配内存的位置,以及是哪些对象分配的。

本文由@W翻译、@海欧校验,感谢大家的参与.如有错译、漏译请留言我们会及时更正。

未经允许,不得转载本站任何文章:代码山 » Chrome DevTools — 查找常见的内存问题

分享到:更多 ()

专注品牌化高端网站建设

商务服务联系我们