内存分析使用的工具包括chrome任务管理器、chrome时间轴(低版本是Timeline,高版本对应performance)、chrome memory(低版本是chrome profiles,主要用JS堆快照、JS堆动态分配时间轴)。文中分析所用chrome版本是68。

  • 使用Chrome任务管理器,了解网页使用的内存量。
  • 使用时间轴记录可视化内存使用。
  • 使用堆快照标识分离的DOM树(内存泄漏的常见原因)。
  • 通过堆动态分配时间轴记录了解在JS堆中分配及回收情况

一、chrome任务管理器

按Shift + Esc打开任务管理器。或点击右上角菜单--更多工具---任务管理器。如下图:

主要关注内存占用空间、Javascript使用的内存。Javascript使用的内存默认不显示,可以点击右键添加。

这两列是在用不同角度来告诉你,网页的内存使用情况︰

  • 内存占用空间表示本机内存。DOM节点存储在本机内存中。如果这个值在增加,则说明正在创建DOM节点。
  • JavaScript 使用的内存列 表示JS堆。这一列包含两个值。关注实际使用大小即可(括号中的数字)。跳动的数字表示您网页上的可获得的对象正在使用多少内存。如果这个数字在增加,那说明正在创建新对象,或现有对象正在增长。

有可能内存占用空间一直在增长,但是JS内存不增长或者缓慢增长。

如果内存占用空间一直在增长但JS内存不增长,可能是浏览器还没有回收,不操作闲置一段时间看下是否会下降。遇到几种情况内存一直不释放(控制台关闭状态下放置三个小时左右),不确定是回收慢,还是浏览器本身存在内存泄露(测试了45、68、69版本):

  • 含密码框(三个版本都有问题)
  • 含输入框,且用户手动输入过值(三个版本都有问题)
  • 含按钮,且用户手动点击过(只有68有问题)

如果是内存占用空间在增长,但JS内存增长得很缓慢,有可能是有JS变量引用了DOM,这个DOM节点本身不大,但影响了其他DOM节点(比如父级节点树)。

二、chrome 时间轴(低版本是Timeline,高版本对应Performance)

Performance(时间轴)面板直观实时显示JS内存使用情况、节点数量、监听器数量等。

  • 打开控制台上的(时间轴)面板。
  • 启用Memory(内存)复选框。
  • 开始录制前先点击垃圾回收-->点击开始录制-->点击垃圾回收-->点击结束录制

你也可以保存录制时间轴或上传以前保存的时间轴

录制结果如下:

这个界面由上往下分别是:

  • Overview的HEAP(堆)曲线图表示JS堆。
  • Call Stack通常来说,垂直方向并没有太大的意义,仅仅表示函数嵌套比较深而已,但是横向表示调用时间,如果调用时间太长,那么就需要优化优化了。录制结果的调用堆栈,横向表示时会出现带有更多详情的浮窗间,垂直方向表示调用栈,从上往下表示函数调用。滑动鼠标滚轮可以查看某段时间的调用栈信息。把鼠标放到Call Stacks调用栈的某个函数上面可以查看函数详细信息。这个一般是性能优化时关注,对于内存泄漏,主要用于帮助定位进行了什么操作。
  • Counter(计数器)窗格。在这里你可以看到内存使用情况(与Overview(概述)窗格中的HEAP(堆)曲线图相同),分别显示以下内容:JS heap(JS堆),documents(文档),DOM nodes(DOM节点),listeners(侦听器)和GPU memory(GPU内存)。勾选或取消勾选复选框可以将其从图表中显示或隐藏。

主要关注第三个的JS堆内存、节点数量、监听器数量。鼠标移到曲线上,可以在左下角显示具体数据。这些数据若有一个在持续上涨,没有下降趋势,都有可能是泄漏。

记得每次开始和结束录制前都点击垃圾回收。另外打开控制台会影响内存的回收,可以录制完后,重新打开不进行任何操作再次录制,与上次的录制进行比对。

上面提到任务管理器出现过“内存占用空间”一直增长,但是“Javascript占用的内存”增长缓慢或不增长的情况。可以关注下节点的数量,可以发现节点数量也一直在增长。

三、chrome Memory(或chrome profiles)

  • 打开控制台上的Memory面板。
  • 选择堆快照类型。我一般是使用前两种:Heap snapshot(JS堆快照)和Allocation instrumentation on timeline(JS堆分配时间线)。
  • 开始录制前先点击下垃圾回收-->点击开始录制。如果JS堆内存动态分配时间线,结束之前要再点击下垃圾回收,再结束录制

录制完可以点击快照进行保存。下次要查看时点击 load 载入文件。

3.1 JS堆快照

  • Summary 总览视图:按构造函数分组。用于捕捉对象及其使用的内存。对于定位DOM内存泄露特别有用。
  • Comparison 对比视图:对比两个快照。用于对比不同操作之后的堆快照,查看内存的释放及引用计数,来分析内存是否泄露及其原因。
  • Containment 内容视图:查看堆内容。更适合查看对象结构,有助于分析对象的引用情况。适用于分析闭包以及深入分析对象。
  • Statistics 统计视图:总览堆的统计信息。

 3.1.1 Summary总览视图

Constructor:构造函数,节点下的对象都是由改构造函数创建而来。
    Distance:与根节点的距离。
    Objects Count:对象个数及百分占比。
    Shallow size:对象的直接内存总数,直接内存是指对象自身占用的内存大小。
    Retained size:对象的最大保留内存,保留内存是指对象被删除后可以释放的那部分内存。
    点击展开构造函数,可以看到所有构造函数相关的对象实例,@后面的数字是该对象实例的唯一标识符。

常见的顶层构造函数:

  • (global property):全局对象和普通对象的中间对象,和常规思路不同。比如在Window上定义了一个Person对象,那么他们之间的关系就是[global] => (global property) => Person。之所以使用中间对象,是出于性能的考虑。
  • (closure):使用函数闭包的对象。
  • (array, string, number, regexp):一系列对象类型,其属性指向Array/String/Number/Regexp。
  • HTMLDivElement/HTMLAnchorElement/DocumentFragment:元素的引用或者代码引用的指定文档对象。

记住,黄色的对象实例表示它被JS代码引用,红色的对象实例表示被黄色节点引用的游离节点。新版本(测试过69)的好像不会有颜色标识。

JS堆快照可以用来发现DOM泄露。在Class filter(类过滤器)文本框中输入Detached可以搜索分离的DOM树。如果分离节点被JS引用,有可能就是泄露点。以下面这段代码为例:

<html>
<head>
</head>
<body>
<button id="createBtn">增加节点</button>
<script>
function create() {  var ul = document.createElement('ul');  for (var i = 0; i < 10; i++) {  var li = document.createElement('li');  ul.appendChild(li);  }  detachedNodes = ul;
}
document.getElementById('createBtn').addEventListener('click', create);
</script>
</body>
</html>

点击一次“增加节点”按钮后,录制快照如下:

发现 有个<ul>分离节点,被window.detachedNodes引用。看下代码原来是没有加var声明,导致其成了全局变量。所以DOM无法释放。

3.1.2 Comparasion对比视图

为了验证特定操作会不会引起内存泄露,对比快照的步骤如下:
    1、无任何操作,拍第一个堆快照
    2、执行你觉得可能造成内存泄露的操作,再执行相反操作
    3、拍第二个堆快照,切换到对照视图,并且指定与第一个堆快照对比

比如你觉得登陆页面内存泄露,那可以先登陆到首页,拍第一个堆快照。然后退出到登陆界面,再重新登陆到首页,录制第二个快照。比对这两个快照的大小,如果增长有可能是泄露,可以反复操作几次。记得每次录制之前要先点击垃圾回收。

3.2 JS堆分配时间线

通过Allocation instrumentation on timeline可以持续的记录堆分配的情况,显示了对象在什么时候被创建、什么时候存在内存泄漏等。

上面的柱条表示堆中生成的新对象。高度表示这个对象的大小,颜色表示这个对象的内存释放情况:蓝色柱表示这个对象在timeline中生成,结束前仍然存在;灰色柱表示这个对象在timeline中生成,但结束前已经被回收了。
我们可以重复执行某个动作,如果最后有不少蓝色柱被保留,这些蓝色柱就是潜在的内存泄露问题。
如果左边的意料之外的蓝条,那么极有可能存在内存泄露。

上面是Vue项目反复切换两个录制的堆分配行为,我们可以聚焦到某一次堆分配,查看具体对象信息。可以在柱状图中滑动鼠标滚轮查看某段时间的堆分配。比如上面发现有三个VueComponent没有回收。点击展开查看详细信息。发现这三个组件的信息都是一样的,那就是组件没有释放。首先确认组件是否被销毁。如果已销毁,确认事件是否解绑、定时器是否取消,特别注意事件总线绑定的事件一定要解绑。

下篇文章将介绍常见内存泄露例子,以及怪异的一些内存增长行为(不确定到底是否算浏览器本身内存泄露)

四、参考文章

1)如何解决Chrome中网页的内存泄露问题

2)Chrome DevTools 之 Profiles,深度性能优化必备

3)如何解决Chrome中网页的内存泄露问题

chrome内存泄露(一)、内存泄漏分析工具相关推荐

  1. 性能优化之内存泄露(Memory Leak)常用分析工具(另3种)

    1 LeakCanary(最常用,能监控整个App内存泄漏情况) 1.1 使用LeakCanary // 仅在debug包启用LeakCanary debugImplementation 'com.s ...

  2. arm linux下交叉编译valgrind工具进行内存泄露检测和性能分析

    C/C++等底层语言在提供强大功能及性能的同时,其灵活的内存访问也带来了各种纠结的问题.如果crash的地方正是内存使用错误的地方,说明你人品好.如果crash的地方内存明显不是consistent的 ...

  3. android分析内存工具,Android Studio内存泄漏分析工具汇总

    Android Studio内存泄漏分析工具汇总 时间:2017-04-25     来源:Android开发学习网 在Android开发过程中,让人头疼的就是内存泄露问题了,很小的一个错误都会引起内 ...

  4. tMemMonitor (TMM) ----- 100%正确的内存泄漏分析工具

    C/C++由于灵活.高效的优点一直以来都是主流的程序设计语言之一,但是其内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放不再使用的内存时就会造成内存泄漏.在大型.复杂的应用程序中, ...

  5. 内存泄漏分析工具tMemMonitor (TMM)使用简介

    内存泄漏分析工具tMemMonitor (TMM)使用简介 C/C++由于灵活.高效的优点一直以来都是主流的程序设计语言之一,但是其内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放 ...

  6. Java内存泄露和内存溢出、JVM命令行工具、.JDK可视化工具、Java Class文件

    1.Java内存泄露和内存溢出对比 1.1 Java 内存泄露 内存泄露是指一个不再被程序使用的对象或变量还在内存中占用空间. 1.1.1判断内存空间是否符合垃圾回收的标准 在Java语言中,判断一个 ...

  7. windows 内存泄露和资源泄漏调试

    AQTime (有x64.win32的)进行内存泄露和资源泄漏监控 http://wenku.baidu.com/view/9aa1c2afdd3383c4bb4cd2c1.html x64下载:ht ...

  8. Java基础恶补——内存泄露、内存溢出

     Java基础恶补--内存泄露.内存溢出 (2010-09-15 15:56:26) 转载 标签: 杂谈 要点 内存泄露是指程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分 ...

  9. Java内存泄露系列--内存泄露的原因及解决方案(大全)

    原文网址:Java内存泄露系列--内存泄露的原因及解决方案(大全)_IT利刃出鞘的博客-CSDN博客 简介 简介 本文介绍Java中内存泄露的一些原因与解决方案. 如果内存泄露的空间足够大,就会导致内 ...

  10. java内存泄露和内存溢出

    内存泄露 是指:对象没有被用到,但是又无法被GC回收就是内存泄露: 分类:经常发生: 发生内存泄露的代码会被多次执行,每次执行,泄露一块内存偶然发生: 在某些特定情况下才会发生一次性: 发生内存泄露的 ...

最新文章

  1. ps怎么把一个颜色替换成另一个颜色_图标设计,用PS制作一款小清新的拟物时钟...
  2. 李飞飞团队给机器人造了一个“模拟厨房”:洗切炒菜一条龙训练!人类还能VR监管 | 开源...
  3. 开发日记-20190627 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 4
  4. 2016年秋季个人阅读计划
  5. CSS中content和attr的用法
  6. 一文了解树在前端中的应用,掌握数据结构中树的生命线
  7. C++网易云课堂开发工程师-拷贝构造,拷贝复制,析构函数
  8. rabbitmq channel对象的方法
  9. 实战 | F1060防火墙透明模式典型组网配置案例(trunk)
  10. centos下 将(jgp、png)图片转换成webp格式
  11. 数据结构:二维ST表
  12. 冒泡python代码_用Python写冒泡排序代码
  13. iOS中使用自定义字体, 动态下载字体
  14. div圆角,阴影效果。
  15. Java基础知识总结(超级经典)
  16. Flutter 中TextField的hintText不居中与光标位置不一致
  17. 小曾带你刷牛客03(Java版本)
  18. 多文件自平衡云传输(四)资源发送端 —————— 开开开山怪
  19. qlikview连接mysql_QlikView 通过ODBC 连接IBM DB2
  20. 月入万元的自由程序员 (转电脑报)

热门文章

  1. Java对接快递鸟跟踪快递物流信息,推送快递轨迹状态
  2. 阿里 P8 熬了两个月肝出这份 32W 字 Java 面试手册,在 Github 标星 31K+
  3. 计网笔记:奈氏准则 香农定理
  4. 解决svg标签在HTML中的渲染问题
  5. 你知道你是個什麼樣的人嗎?
  6. 碉堡了! 纯 CSS 绘制《辛普森一家》人物头像
  7. Element制作一个简洁的个人信息界面附带简单的双向绑定
  8. 解决Visual Studio的IIS与无法启动调试器问题
  9. 错误:org.apache.jasper.JasperException 无法为JSP编译类
  10. mysql bdb_MySQL在Red Hat 7.0上的BDB表配置