如何看内存占用情况,vue反复刷新标签页导致面内存一直在涨,系统反应越来越慢,内存占用4个g。

胡八一、 2024-07-23 16:03:04 阅读 59

1、内存泄漏与内存溢出

内存泄漏(Memory Leak): 不再用到的内存,没有及时释放;

内存溢出(Out Of Memory): 应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。

2、泄漏原因

<code>js写法(闭包、全局变量等)、dom事件监听、循环定时器等这些造成的泄漏;

组件的泄漏(DOM泄漏即DOM无法销毁)导致DOM上挂载的事件,对象数组等的数据也跟着无法释放。

3、chrome Memory 介绍

打开控制台上的Memory面板或者按住F12打开。

选择堆快照类型。我一般是使用前两种:Heap snapshot(JS堆快照)Allocation instrumentation on timeline(JS堆分配时间线)

开始录制前先点击下垃圾回收–>点击开始录制。如果JS堆内存动态分配时间线,结束之前要再点击下垃圾回收,再结束录制。

在这里插入图片描述

4、解决办法

4.1、JS堆快照

<code>Summary 总览视图: 按构造函数分组。用于捕捉对象及其使用的内存。对于定位DOM内存泄露特别有用。

Comparison 对比视图: 对比两个快照。用于对比不同操作之后的堆快照,查看内存的释放及引用计数,来分析内存是否泄露及其原因。

Containment 内容视图: 查看堆内容。更适合查看对象结构,有助于分析对象的引用情况。适用于分析闭包以及深入分析对象。

Statistics 统计视图: 总览堆的统计信息。

Summary总览视图

在这里插入图片描述

说明:

<code>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>code>

<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 >分离节点,被<code>window.detachedNodes引用。看下代码原来是没有加var声明,导致其成了全局变量。所以DOM无法释放。

Comparasion对比视图

为了验证特定操作会不会引起内存泄露,对比快照的步骤如下:

1、无任何操作,拍第一个堆快照

2、执行你觉得可能造成内存泄露的操作,再执行相反操作

3、拍第二个堆快照,切换到对照视图,并且指定与第一个堆快照对比

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

使用对比可以看到第一次和第二次快照不同地方

在这里插入图片描述

注意:

<code>Chrome开发者工具中Memory功能排查,你会发现怎么每个组件都存在内存泄漏,导致无从下手

这时候我们就要采用排除法来找出泄露点,之前说过是切换主菜单时发生内存泄漏,那首先把每个菜单页面内容全注释,再切换主菜单,经测试没有内存泄漏。

查看快照Containment view 内容视图

内容视图其实就是应用对象结构的鸟瞰图。它能让你深入分析函数闭包,观察VM内部对象,查看应用底层的内存使用情况。

在这里插入图片描述

该视图提供了几个常见入口:

<code>DOMWindow objects:JavaScript代码的全局对象Native objects:浏览器的原生对象,整合到JS虚拟机中便于操作,比如DOM节点,CSS规则。

关于闭包的一个小建议:命名函数的闭包相对匿名函数的闭包更易于分析调试。

// 匿名闭包

function createLargeClosure() {

var largeStr = new Array(1000000).join('x');

var lC = function() {

return largeStr;

};

return lC;

}

// 命名闭包

function createLargeClosure() {

var largeStr = new Array(1000000).join('x');

var lC = function lC() {

return largeStr;

};

return lC;

}

在这里插入图片描述

查看快照Statistics 统计视图

总览堆栈的统计信息。可以清楚的看出堆快照的分布情况。

在这里插入图片描述

4.2、JS堆分配时间线

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

在这里插入图片描述

上面的柱条表示堆中生成的新对象。高度表示这个对象的大小,颜色表示这个对象的内存释放情况:蓝色柱表示这个对象在<code>timeline中生成,结束前仍然存在;灰色柱表示这个对象timeline中生成,但结束前已经被回收了。

我们可以重复执行某个动作如果最后有不少蓝色柱被保留,这些蓝色柱就是潜在的内存泄露问题。

如果左边的意料之外的蓝条,那么极有可能存在内存泄露。

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

在这里插入图片描述

要注意<code>VueComponent的泄漏值,因为VueComponent是会挂载对象、数据、事件的,所以那些Object Array产生泄漏值也很大可能是VueComponent造成的。所以我们在处理泄漏的时候最好是先保证VueComponent的泄漏值为0. 然后再去往js闭包、循环定时器、事件监听那些方向去检查。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。