内存分析使用的工具包括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引用,有可能就是泄露点。以下面这段代码为例:
</head>
<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
-> 设置 -> More Tools -> Task Manager
确保 Task Manager 的 Memory Footprint 与 JavaScript Memory 列已显示
表格列右键,勾选需要显示的列
在系统中随意操作,或模拟用户正常操作
观察 Task Manager 中的使用情况,如符合一下特征的基本可以确定存在
内存泄露
每次操作
内存
均有所上升
操作较长时间后
内存
持续一直上涨
使用 DevTools 辅助判
http://blog.csdn.net/kaitiren/article/details/19974269
内存泄露
不错的帖子,感谢分享
Google
Chrome
浏览器提供了非常强大的JS调试
工具
,Heap Profiling便是其中一个。Heap Profiling可以记录当前的堆
内存
(heap)快照,并生成对象的描述文件,该描述文件给出了当时JS运行所用到的所有对象,以及这些...
如何
分析
代码执行耗时
代码执行耗时这块,大家应该都知道使用 Performance 面板中的 火焰图,火焰图中每个方块的宽度代表执行耗时,方块叠加的深度代表调用栈的深度。通过火焰图可以很直观地展示出代码调用关系,当你不熟悉某个框架、源码中的代码逻辑,又不希望一行行去看源码,火焰图就是最好的
工具
。
在
分析
性能的时候,为排除插件的影响,需要启用无痕模式
此外我们还可以看到每一行代码执行的时间。在火焰图中找到长任务,点击顶部 Task,点击 Button-Up,这时候可以看到根据耗时列出的调用栈:
DevTools 显示了按功能划分的
内存
分配细目。 默认视图是 Heavy (Bottom Up),它在顶部显示分配最多
内存
的函数。
Fix memory problems
内存泄漏
很容易定义。 如果一个站点逐渐使用越来越多的
内存
,那么您就会出现泄漏。 但是
内存
膨胀有点难以确定。 什么是“使用过多
内存
”?
这里没有硬性数字,因为不同的设备和浏览器具有不同的功能。 在高端智能手机上流畅运行的同一页面在低端智能手机上可能会崩溃。
这里的关键是使用 RAIL 模型并关注您的用户。 找出哪些设备受用户欢迎,然后在这
当以服务器端渲染模式运行的 Web 应用的 Node.js 进程遇到
内存泄漏
问题时,通常我们能够观察到注意到频繁的
内存
峰值和 pod 重启,如下图 Dynatrace
工具
所示:
分析
内存泄漏
问题的关键是在不同的时间点收集多个
内存
转储(Memory Dump),并比较每个收集之间的对象增长,例如 在 Pod 重新启动后不久和
内存
饱和之前不久。
可以在
Chrome
中从浏览器开发
工具
>
内存
(应选择堆快照)> 加载进行 Memory Dump 的搜集和加载操作。
在不同的时间段内进行 Me
在了解过浏览器
内存
模型以及事件循环之后,这仅仅是从一个代码的运行上了解了我们前端工程师编写的code是怎么样存储的以及怎么样去运行,了解了这些之后,我们就需要了解怎么样去使用合适的
工具
追踪我们
内存
中的变量以及运行中的代码,以加深我们对整个前端环境的理解、提高前端开发以及查找
内存
漏洞的效率,同时可以更加迅速的对前端页面加载等优化作出更好的决策。...
JavaScript,会在创建变量(对象,字符串等)时分配
内存
,并且在不再使用它们时“自动”释放
内存
,这个自动释放
内存
的过程称为垃圾回收。
因为自动垃圾回收机制的存在,让大多Javascript开发者感觉他们可以不关心
内存
管理,所以会在一些情况下导致
内存泄漏
。
内存
生命周期
JS 环境中分配的
内存
有如下声明周期:
内存
分配:当我们申明变量、函数、对象的时候,系统会自动为他们分配
内存
开发过程中难免会遇到
内存
问题,emmm... 本文主要记录一下
Chrome
排查
内存
问题的面板,官网也有,但有些说明和例子跟不上新的版本了,也不够详细...
!!! 多图预警!!!
简单的
内存
信息列表
如果只想查看当前浏览器的各个 tab 正在使用的
内存
量,则在 Setting - More Tools - Task Manager即可。效果如下图:...
Memory面板是
Chrome
DevTools中的一个功能强大的
工具
,用于帮助开发者监控并
分析
页面的
内存
使用情况,可以帮助发现和解决
内存泄漏
和性能问题。可以通过Memory面板的快照功能对页面进行
内存
快照,并
分析
每个对象的
内存
使用情况,包括对象的类型、大小、引用关系等信息。可以通过比较两个
内存
快照的差异,发现哪些对象被长时间保持引用而没有被释放,从而定位
内存泄漏
问题。可以通过记录
内存
分配事件,
分析
页面中的
内存
分配情况,找出
内存
分配过程中的性能瓶颈。