js内存泄漏及排查详解

2023-10-27

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上跳转到代码所在行,有时候对定位问题也很有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js内存泄漏及排查详解 的相关文章

随机推荐

  • 关于kali安装nessus打不开网页?

    大家好 我想请教大家一个问题 我在kali上面安装的是10 4版本的nessus 后来压缩到tmp之后 我复制到etc里 我开启了这个nessus服务 但是显示这个 我擦 不知道怎么回事 换了一个8版本的也不行 然后最终的问题就是浏览器打不
  • 数据类型和取值以及运算符

    数据类型分为基本数据类型和引用数据类型 一 基本数据类型又分为 1 数值型 byte short int long float double 2 布尔型 booleanl 3 字符型 char 二 引用数据类型 类 接口 抽象类 数组 常用
  • 大一统,windows下安装linux的最新方式

    抛弃虚拟机和双系统 在windows下使用linux 为啥要执着于linux 入坑指南 安装windows terminal 开启子系统功能 下载Ubuntu系统 更改命令主题 把oh my zsh 项目 Clone 下来 复制 zshrc
  • RFC2367 PF_KEY键管理API

    组织 中国互动出版网 http www china pub com RFC文档中文翻译计划 http www china pub com compters emook aboutemook htm E mail ouyang china p
  • 基于C++的非线性方程的解法研究及实现

    基于C 的非线性方程的解法研究及实现 前言 关于非线性方程f x 0的根的解法目前分为三类 二分法 试值法和不动点迭代法 本文实例为寻找f x x2 2x在区间 1 3 内精度在0 05以内的实根 代码中的set用于保存答案 1 二分法 二
  • 华为云服务器最新信息,云服务器拉新

    云服务器拉新 内容精选 换一换 当云服务器密码即将过期 密码泄露或首次登录时 首次登录云服务器建议您修改初始密码 您可以参考本节操作在操作系统内部修改云服务器密码 优先推荐您参考在控制台重置云服务器密码 在控制台重置实例的登录密码 可以登录
  • 手把手教你如何自己设计实现一个深度学习框架(附代码实现)

    本文首先从深度学习的流程开始分析 对神经网络中的关键组件抽象 确定基本框架 然后再对框架里各个组件进行代码实现 最后基于这个框架实现了一个 MNIST 分类的示例 并与 Tensorflow 做了简单的对比验证 喜欢本文 就请点赞 收藏 关
  • HBase写吞吐场景资源消耗量化分析及优化

    一 概述 HBase 是一个基于 Google BigTable 论文设计的高可靠性 高性能 可伸缩的分布式存储系统 网上关于 HBase 的文章很多 官方文档介绍的也比较详细 本篇文章不介绍HBase基本的细节 本文从 HBase 写链路
  • Jupyter 如何使用 args = parser.parse_args()

    最近在女朋友的催促下 啃代码啃得脑壳疼 遇到了一个问题 python文件里面的参数不能直接在jupyter中使用 放在jupyter中的时候就会报错 如下所示 parser argparse ArgumentParser parser ad
  • Vscode配置C/C++环境出现报错,导致不能运行代码,报错如下:

    Vscode配置C C 环境出现报错 导致不能运行代码 报错如下 问题描述 gcc 无法将 gcc 项识别为 cmdlet 函数 脚本文件或可运行程序的名称 请检查名称的拼写 如果包括路径 请确保路径正确 然后再试一次 所在位置 行 1 字
  • YUV学习,详解

    YUV 格式详解 只看这一篇就够了 分类标准 首先 我们可以将YUV格式按照数据大小分为三个格式 YUV420 YUV422 YUV444 由于人眼对Y的敏感度远超于对u和v的敏感度 所以有时候可以多个Y分量共用一组uv 这样既可以极大的节
  • Dreaming to Distill: Data-free Knowledge Transfer via DeepInversion

    Dreaming to Distill Data free Knowledge Transfer via DeepInversion 1 论文信息 论文标题 Dreaming to Distill Data free Knowledge T
  • java基础语法(精简版)

    文章目录 目录 文章目录 一 运算符 1 算数运算符 2 赋值运算符 3 关系运算符 比较运算符 4 逻辑运算符 5 三元运算符 6 字符的 操作 7 字符串的 操作 二 流程控制语句 1 顺序结构 2 分支结构 1 if语句 2 swit
  • Win10 系统下VisualStudio2019 配置点云库 PCL1.11.0

    目录 一 下载PCL1 11 0 二 安装PCL1 11 0 三 VS2019相关设置 四 配置PCL1 11 0 五 测试代码 六 附录 获取自己的链接库列表 一 下载PCL1 11 0 Github下载地址 https github c
  • docker: Error response from daemon: driver failed programming external connectivity on endpoint ranc

    docker Error response from daemon driver failed programming external connectivity on endpoint rancher server f62779d6c72
  • oracle--查询练习

    查询练习 1 查询工资大于12000的员工姓名和工资 select last name salary from employees where salary gt 12000 2 查询员工号为176的员工的姓名和部门号 select las
  • Qt基础-使用QSettings保存读取配置文件

    Qt基础 使用QSettings保存读取配置文件 QSettings类简介 存储 读取 QSettings类简介 QSettings可以用来存储或读取配置文件 不同于普通文本格式的字符串存取方式 QSettings可以存储bool值 字体Q
  • mysql 子查询

    一 mysql子查询 1 1 子查询定义 子查询 Sub Query 或者说内查询 Inner Query 也可以称作嵌套查询 Nested Query 是一种嵌套在其他 SQL 查询的 WHERE 子句中的查询 子查询用于为主查询返回其所
  • Java中的 BigDecimal正常使用

    点击关注 芋道源码 2022 04 10 10 33 收录于话题 芋道源码688个 点击上方 芋道源码 选择 设为星标 管她前浪 还是后浪 能浪的浪 才是好浪 每天 10 33 更新文章 每天掉亿点点头发 源码精品专栏 原创 Java 20
  • js内存泄漏及排查详解

    js内存泄漏及排查详解 常见内存泄漏及解决方案 内存泄漏 Memory Leak 是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放 造成系统内存的浪费 导致程序运行速度减慢甚至系统崩溃等严重后果 隐式全局变量 在局部作用域中 等