js内存泄漏及排查详解

news2024/9/20 12:13:50

js内存泄漏及排查详解

常见内存泄漏及解决方案

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

隐式全局变量

在局部作用域中,等函数执行完毕,变量就没有存在的必要了,浏览器的垃圾回收机制很快进行回收,但是对于全局变量,很难判断什么时候不用这些变量,无法正常回收;所以,尽量少使用全局变量。

function foo() {
  a = 'test'
}
// 上面的写法等价于
function foo() {
  window.a = 'test'
}

上面的a变量应该是foo()内部作用域变量的引用,由于没有使用关键词(letconstvar)来声明这个变量,这时变量a就被创建成了全局变量,这时候就会导致内存泄漏。

解决方式:使用 varletconst 来定义变量。或者在js文件开头添加 'use strict',开启严格模式。

function bar() {
  this.a = 'test'
  // 函数自身发生调用,this指向全局对象window
}
bar();

闭包

闭包是代码块和创建该代码块的上下文中数据的结合(函数套函数,子函数引用了父函数的参数或变,并且被外部引用,形成不被释放的作用域)。

在使用闭包的时候,就会造成严重的内存泄漏,因为闭包中的局部变量,会一直保存在内存中。

function fn(){
  let result = {}
  return function(){
    // 因为闭包内引用了result,导致它不会被垃圾机制回收,导致内存泄漏
    return result;
  }
}
let fn1 = fn()
fn1()

上面的代码可以直接通过将fn1置为null来清除引用。也可以少用闭包的方式。

未清除的DOM引用

<div id="app">
  <ul id="ul">
    <li></li>
    <li></li>
    <li id="li3"></li>
    <li></li>
  </ul>
</div>
<script>
  let app = document.querySelector('#app')
  let ul = document.querySelector('#ul')
  let li3 = document.querySelector('#li3');
  app.removeChild(ul);
</script>

上面的代码虽然调用removeChildulDOM上移除了,但是由于ul变量中仍存在引用,整个ul及子元素都不能被垃圾回收机制清除。

因此需要手动将引用清除:

ul = null;

但是此时li3变量还引用着ul的子节点,ul还是不能够垃圾回收机制清除,还需要手动将li3解除引用。

li3 = null;

定时器

setInterval或者setTimeout在不需要使用的时候,没有被clear,导致定时器的回调函数及其内部依赖的变量都不能被回收,这也会造成内存泄漏。另外,浏览器中的 requestAnimationFrame 也存在这个问题,在不需要的时候用 cancelAnimationFrame 来取消使用。

const data = {};
setInterval(() => {
  console.log(data);
}, 1000)

循环引用

循环引用 在引用计数策略下会导致内存泄漏,标记清除不会。

function fn() {
  const a = {};
  const b = {};
  a.b = b;
  b.a = a;
} 
fn();

ab的引用次数都是2,fn()执行完毕后,两个对象都已经离开环境。
在标记清除方式下是没有问题的,但是在引用计数策略下,ab的引用次数不为0,不会被垃圾回收器回收内存。如果fn函数被大量调用,就会造成内存泄漏,这时候就需要手动解除引用(置为null)。

未清理的console

如果在console中输出了对象,那么浏览器就需要把这个引用关系保存下来,才能在控制台上看到相应的对象,这样同样也会造成内存泄漏。

使用chrome devtool工具排查内存泄漏问题

查看内存曲线

在浏览器中打开开发者工具(通常都是F12快捷键打开)。首先可以查看Performance栏。

在这里插入图片描述
勾选memory,点击左上角的原点开始录制一段时间,如果出现内存曲线没有明显下降,说明可能存在内存泄漏。

查看内存情况

performance栏中如果看到曲线没有明显下降, 那么这时候就可以点击memory栏去查看更多的信息。

在这里插入图片描述
同样开始点击左上角的原点开始记录,通常需要录制多几遍(每次录制前都先点击垃圾回收按钮先回收掉可以收集的垃圾),然后进行对比。

在这里插入图片描述
这里可以很明显看到内存占用一次比一次高,选择快照对比,进行内存泄漏的排查。

在这里插入图片描述
首先可以先查看shallow size(对象本身占用内存的大小,不包含其引用的对象),retained size(对象本身的Shallow Size + 对象能直接或间接访问到的对象的Shallow Size),如果retained size远大于shallow size,说明就是这里有泄漏。

在这里插入图片描述
在这个记录中,示例代码是通过新增了19个隐式全局变量且每个变量的值new Array(100000)都是导致的内存泄漏。

而对于未清除的DOM引用,我们可以查看快照中有没有Detached XXXXElement对象。

在这里插入图片描述

建议

文章中使用的demo都是简单的,对于项目中想排查问题来说多了非常多变量,想要定位问题比较困难,这里个人列举几个比较有用的建议:

  1. 尽量使用没有混淆的代码:

打包后的代码往往经过了混淆和压缩,在生产环境上这是必要的,但在debug时却会成为我们的绊脚石,不便于阅读。

  1. 排查问题时使用production模式编译出来的代码:

dev模式下往往会开启一些方便开发的特性,例如热更新等。但它们可能会占用一部分的内存,影响到内存问题的排查,所以建议还是使用production模式编译出来的代码进行问题排查。

  1. 屏蔽所有浏览器插件:

屏蔽浏览器插件最快的方式就是打开无痕窗口。浏览器插件给我们带来很多便利,但插件注入的额外逻辑有时也会影响内存问题的排查。例如vue-devtools会记录下每一个vuex mutaions,导致内存无法释放。

  1. 在现场打内存快照,便于跳转到源代码所在行:

尽管devTools记录下来的内存快照文件可以单独加载展示,但还是建议在记录下内存快照的时候“趁热”分析,因为这时还能从retaining tree上跳转到代码所在行,有时候对定位问题也很有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/698072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

音频小说项目介绍

看小说、听音频&#xff0c;App,H5网站&#xff0c;小程序多端开发 一、主页 主页tabBar四个分类&#xff1a; 首页&#xff0c;分类&#xff0c;收藏&#xff0c;我的 最上方是搜索框 下方是轮播图&#xff0c;不但自动滚动&#xff0c;还有动画效果 下面分类有&#xf…

IDEA 或者SVN修改老项目的svn地址

公司svn地址修改了&#xff0c;ip修改了。本地还有代码没提交。这里介绍一下怎么在IDEA或svn修改为新地址&#xff0c;然后代码就可以直接提交了。网上也有文章介绍&#xff0c;但其中没注明一个关键点&#xff0c;导致很多人修改不成功。所以有了这篇文章。 IDEA下修改svn地址…

【Python】模块导入 ⑤ ( 主程序判断语句 | 模块中执行函数问题 | 制作自定义模块并执行函数 | 导入自定义模块会执行模块中的代码 )

文章目录 一、模块中执行函数问题1、制作自定义模块并执行函数2、导入自定义模块会执行模块中的代码3、主程序判断语句4、代码示例 - 主程序判断语句 一、模块中执行函数问题 1、制作自定义模块并执行函数 如果在自定义模块中 , 定义了函数 , 并且调用了该函数 ; 如下代码所示…

【TCP/IP】多播 - 定义、原理及编程实现 (TTL、多播组、多播消息)

目录 多播 多播的原理 多播的数据传输时的特点 TTL 的概念 TTL 和 多播组的配置方法 多播的编程与实现 发送者 接收者 多播 多播是一种介于单播和广播通信之间的技术方式&#xff0c;可以将发送者所需要发送的数据包分别发送给分散在不同子网中的一组接收者。 多播的原…

MySQL - 第11节 - MySQL事务管理

1.事务的概念 事务的概念&#xff1a; • 上层看起来比较简单的需求&#xff0c;可能对应的后端要做很多工作&#xff0c;后端这些工作组合起来才是一个完整的需求解决的方案。 • 事务由一条或多条SQL语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;共同完成一个…

聊聊transformers库; 微软推出ZeRO++技术:优化大型AI模型训练时间和成本

&#x1f989; AI新闻 &#x1f680; 微软推出ZeRO技术&#xff1a;优化大型AI模型训练时间和成本 摘要&#xff1a;据报道&#xff0c;微软研究人员最近发布了一项名为ZeRO的新技术&#xff0c;旨在优化训练大型AI模型时常遇到的数据传输成本和带宽限制问题&#xff0c;可大…

【0212】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13 - 2)

文章目录 1. 回顾2. 密码校验通过3. 密码校验失败上一文:【0211】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13 - 1) 1. 回顾 在上一节内容中,讲解了Backend对于接收到来自frontend的字符串明文密码,和来自于来自pg_auth…

荷兰宽带数据泄露 1

又要引入一个新工具RouterPassView 大多数现代路由器都可以备份一个路由器的配置文件&#xff0c;然后在需要的时候从文件中恢复配置。路由器的备份文件通常包含了像您的ISP的用户名重要数据/密码&#xff0c;路由器的登录密码&#xff0c;无线网络的KEY。 如果你忘记了这些密码…

第八十九天学习记录:C++核心:引用

引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名原名 #include<iostream> using namespace std;int main() {//引用基本语法//数据类型 &别名 原名int num1 3;int &num2 num1;cout << "num1" << n…

输入路由器IP地址进入IIS问题解决

0x01 问题描述 Windows10系统&#xff0c;路由器IP为192.168.1.1&#xff0c;本机获取的IP为192.168.1.110&#xff0c;但在浏览器URL输入路由器IP时却没有进入路由登录页&#xff0c;而是进了IIS欢迎页面。 0x02 问题分析 由于我本机IP不是192.168.1.1&#xff0c;所以排除与…

第八十七天学习记录:Linux基础:基础指令Ⅱ

touch创建文件 可以通过touch命令创建文件 语法&#xff1a;touch Linux路径 1、touch命令无选项&#xff0c;参数必填&#xff0c;表示要创建的文件路径&#xff0c;相对、绝对、特殊路径符均可以使用 cat命令 查看文件内容 首先用Vim编辑器在刚刚新建的tanktest.txt中编辑…

MyBatis学习笔记--中篇

MyBatis学习 文章目录 MyBatis学习1、MyBatis 配置解析1.1、核心配置文件1.2、事务管理器&#xff08;transactionManager&#xff09;1.3、数据源&#xff08;DataSource&#xff09;1.4、属性&#xff08;properties&#xff09;1.5、类型别名&#xff08;typeAliases&#x…

1. AGPC-SLAM: Absolute Ground Plane Constrained 3D Lidar SLAM

AGPC-SLAM: Absolute Ground Plane Constrained 3D Lidar SLAM overview 关键思路 odom约束 回环检测约束 地面约束 总体约束 问题 地面约束似乎倾向于全部对齐到第一个平面&#xff0c;也就是说该方案假设了所有地面方程是同一个平面。后面的实验也验证了上述假设有问题&…

EfficientDet(EfficientNet+BiFPN)论文超详细解读(翻译+学习笔记+代码实现)

前言 在之前我们介绍过EfficientNet&#xff08;直通车&#xff1a;【轻量化网络系列&#xff08;6&#xff09;】EfficientNetV1论文超详细解读&#xff08;翻译 &#xff0b;学习笔记代码实现&#xff09; 【轻量化网络系列&#xff08;7&#xff09;】EfficientNetV2论文超详…

Linux:etc/group

etc/group文件中保存着系统中所有组的名称&#xff0c;以及每个组中的成员列表。 文件中的一行为一个组的信息&#xff0c;具体如下&#xff1a; 如果组口令字段为x的话&#xff0c;就还有一个etc/gshadow文件用于存放组口令。 GID用于标识一个组&#xff0c;应保证其唯一性。…

Spring Boot 中的事务回滚规则

Spring Boot 中的事务回滚规则 在应用程序中&#xff0c;事务管理是一个重要的概念。事务是指一系列的操作&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败。在Spring Boot中&#xff0c;我们可以使用事务管理器来管理事务。在使用事务管理器的时候&#xff0c;一个…

ElasticSearch——复合查询

Elasticsearch 语雀&#xff08;完整笔记&#xff09; 复合&#xff08;compound&#xff09;查询&#xff1a;复合查询可以将其它简单查询组合起来&#xff0c;实现更复杂的搜索逻辑。常见的有两种&#xff1a; fuction score&#xff1a;算分函数查询&#xff0c;可以控制…

《计算机系统与网络安全》第七章 身份认证

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【单片机】STM32单片机读取旋转编码器,TIM定时器捕获

文章目录 旋转编码器介绍主程序逻辑直接检测用外部中断检测下降沿定时器直接解码旋转编码器 旋转编码器介绍 旋转编码器简单来说&#xff0c;就是会输出2个PWM&#xff0c;依据相位可以知道旋转方向&#xff0c;依据脉冲个数可以知道旋转的角度。一般旋转一圈有一个固定数值的…

chatgpt赋能python:Python输出\n的用法及优势

Python 输出\n 的用法及优势 在Python编程语言中&#xff0c;我们常常需要输出字符串&#xff0c;并在特定地方换行。在这种情况下&#xff0c;使用\n是一种非常方便的方式。在本文中&#xff0c;我们将详细介绍Python的输出\n的用法及其优势。 什么是\n&#xff1f; \n是一…