前端内存泄漏和溢出的情况以及解决办法

2023-11-06

写在前面:

在平时写代码时,内存泄漏的情况会时有发生,虽然js有内存回收机制,但在平时编程中还是需要注意避免内存泄漏的情况;前几天做移动端时遇到一个内存泄漏造成移动端页面卡顿的问题,所以想总结下前端内存泄漏的情况,回顾下基础知识

一、什么是内存泄漏

 程序运行时操作系统会分配相应的内存,如果不进行定时的清理内存的占用情况,内存占用越来越高,很容易造成页面卡顿,进程奔溃;如果程序在系统分配了内存空间后不再使用但是没有及时释放就会造成内存泄漏;程序向系统申请的内存空间超出了系统能给的,就造成了内存溢出。内存泄漏和溢出都会影响程序的性能。

js不需要手动给变量申请内存,当我们在申明一个变量时,js会自动为其分配内存;当某个对象没有被引用会进行回收,最简单的垃圾回收机制是引用计数,当某个对象被引用的次数达到0时就会被回收

二、常见的造成内存泄漏的情况

1.全局变量:一个变量被挂载到window上,那么它永远都是可达的,只有关闭页面或关闭浏览器时被回收。严格模式下可以避免这个情况;解决方法:testVal = null

局部变量:在函数执行过后,局部变量就被回收了,此时便可以将它引用的内存释放掉

另一种全局变量可能由this创建

function foo() {
    this.variable = "potential accidental global";
}
// foo 调用自己,此时this 指向了全局对象(window)
foo();

2.定时器

使用定时器时,我们销毁了这个DOM,但是在定时器中使用了这个DOM,定时器中就保留了对这个DOM的引用,所以需要在清除DOM时也要手动清除定时器(timer = null)

var someResource = getData();
const timer = setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

解决:document.body.removeChild(node);someResource = null

timer = null ,这样定时器中的node 和someResource才会真的被回收掉

3.闭包函数导致的泄漏

闭包可以维持函数内部的局部变量,使其变量得不到释放

function bindEvent() {
  var obj = document.createElement('XXX');
  var unused = function () {
    console.log(obj, '闭包内引用obj obj不会被释放');
  };
  obj = null; // 解决方法
}

4.DOM元素的事件监听

btn.addEventListener('click', onClick)
btn.removeEventListener('click', onClick)

5.没有清理对DOM元素的引用

const refA = document.getElementById('refA');
document.body.removeChild(refA); // dom删除了
console.log(refA, 'refA'); // 但是还存在引用,能console出整个div 没有被回收
refA = null;  // 这里会报错  Assignment to constant variable(赋值给常数变量).因为这个refA是const声明的,值不可以改变,将const改为var
console.log(refA, 'refA'); // 解除引用

三、Vue中占用内存的几种情况

1.全局变量在切换页面时没有清空

mounted() {
      window.test = {
        // 此处在全局window对象中引用了本页面的dom对象
        name: 'home',
        node: document.getElementById('home'),
      }
    },

解决:在页面卸载时顺便清空该引用

destroyed(){

  window.test = null

}

2.监听在window或body上的事件没有解绑

  • 如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
  • 如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
  • 如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
  • 某些组件在模板中使用 事件绑定可能会出现泄漏,使用$on 替换模板中的绑定

如果是要render函数,避免在html标签中DOM / BOM事件

mounted () {
  window.addEventListener('resize', this.func)
},
methods:{
    func(){}
}

// 解决:
beforeDestroy () {
  window.removeEventListener('resize', this.func)
}

3.在进入页面时打开弹框dialog,在离开页面时没有设为false

mounted () {
  this.Dialog = true
},

// 在手动点击头部的返回按钮和回到首页的按钮时,会造成页面卡顿,无法滑动的问题

// 在离开页面时将它设为false
  beforeRouteLeave(to, from, next){
    this.Dialog = false
    next()
  },

 4.绑在EventBus的事件没有解绑

解决:页面卸载时解除引用

mounted () {
 this.$EventBus.$on('homeTask', res => this.func(res))
},
destroyed () {
 this.$EventBus.$off()
}

5.v-if指令产生的内存泄漏

在使用v-if来控制显示隐藏的时候,当v-if的条件为false时,浏览器不会渲染这个元素;但是当我们在v-if为true时,给这个元素内添加了其他子元素,那么我们在设为false的时候只是这个父元素本身从虚拟DOM中移除它,新添加的子元素并没有移除,子元素对父元素引用了,父元素也就不会被移除

例子:

<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div>

原来的写法

<script>
  export default {
    data() {
      return {
        showChoices: true,
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        // 我们来为选择框载入很多选项,这样的话它会占用大量的内存
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
        new Choices('#choices-single-default', {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        this.showChoices = false
      },
    },
  }
</script>

处理后的写法:我们在hide方法里移除父元素时对子元素做一个清理

<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div>
</div>
 
<script>
  export default {
    data() {
      return {
        showChoices: true,
        choicesSelect: null
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
         // 在我们的 Vue 实例的数据对象中设置一个 `choicesSelect` 的引用
        this.choicesSelect = new Choices("#choices-single-default", {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        // 现在我们可以让 Choices 使用这个引用,从 DOM 中移除这些元素之前进行清理工作
        this.choicesSelect.destroy()
        this.showChoices = false
      },
    },
  }
</script>

 6.echart图表带来的内存泄漏

每一个图例在没有数据的时候它会创建一个定时器去渲染气泡,页面切换后,echarts 图例是销毁了,但是这个 echarts 的实例还在内存当中,同时它的气泡渲染定时器还在运行。这就导致 Echarts 占用 CPU 高,导致浏览器卡顿,当数据量比较大时甚至浏览器崩溃。

解决方法:加一个 beforeDestroy()方法释放该页面的 chart 资源,我也试过使用 dispose()方法,但是 dispose 销毁这个图例,图例是不存在了,但图例的 resize()方法会启动,则会报没有 resize 这个方法,而 clear()方法则是清空图例数据,不影响图例的 resize,而且能够释放内存,切换的时候就很顺畅了。

beforeDestroy () {
  this.chart.clear()
}

ES6中防止内存泄漏

在平时编程中我们可能没有及时的清除引用,ES6中新增了两种数据结构:weakset 和 weakmap,他们对值得引用时不计入垃圾回收机制的,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存。

const wm = new WeakMap()
const element = document.getElementById('example')
vm.set(element, 'something')
vm.get(element)

上面代码中,先新建一个 Weakmap 实例。然后,将一个 DOM 节点作为键名存入该实例,并将一些附加信息作为键值,一起存放在 WeakMap 里面。这时,WeakMap 里面对 element 的引用就是弱引用,不会被计入垃圾回收机制。

注册监听事件的 listener 对象很适合用 WeakMap 来实现

<div id="example">点击</div>

// 代码1
element.addEventListener('click', handler, false)
 
// 代码2
const listener = new WeakMap()
listener.set(element, handler)
element.addEventListener('click', listener.get(element), false)

function handler(){
    console.log('测试')
}

好处是:由于监听函数是放在 WeakMap 里面,一旦 dom 对象 ele 消失,与它绑定的监听函数 handler 也会自动消失。

以上总结有些是平时工作中遇到的需要注意的点,有些是借鉴别人的blog:

前端常见内存泄漏及解决方案_傲娇的koala的博客-CSDN博客

 https://mp.weixin.qq.com/s/TEs6JKQsRo2ZbVhVfAuOBA

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

前端内存泄漏和溢出的情况以及解决办法 的相关文章

  • 如何在 Firefox 控制台中访问附加内容脚本?

    我为 Firefox 和 Chrome 开发了一个插件 它有内容脚本 我想在浏览器选项卡的控制台中访问它们 在 Firefox 上网页控制台 https developer mozilla org en US docs Tools Web
  • 第一次使用node.js - “ReferenceError:节点未定义”

    我刚刚安装了node js 我尝试编写应该检查版本的node v 但它不起作用 这是输出 gt node v ReferenceError node is not defined at repl 1 2 at REPLServer self
  • 如何导入和导出 javascript ES6 类

    我是 javascript 和 nodejs 的新手 我正在使用这个项目来发展我的技能并学习新技术 目前我的项目使用多个相互依赖的类 类文件位于不同的目录中 我当前正在尝试使用 export 和 require 语句来允许在其他文件中引用类
  • 搜索深度嵌套数组以更新对象

    我有一个深层嵌套的数据结构 我有兴趣匹配数组 和数组数组 中的某个值 然后将一些数据推送到随附的数组中 例如以下是我的数组colors并伴随着的是更多颜色数组可能存在也可能不存在 var myData color green moreCol
  • 确定元素是在页面折叠上方还是下方

    我有一些页面有多个输入框 用户可以在其中输入文本 在单击 下一步 按钮之前 需要填写其中一些内容 我弹出验证错误供用户查看 但是如果问题不在页面上 我希望页面滚动到它 而不是他们必须搜索丢失 错误的字段 我有一个滚动到位 但我无法确定要滚动
  • 通过JS Laravel访问存储目录

    有没有办法访问storage目录 该目录已经链接到publicJS 中的目录 我正在尝试制作一个上传图片的表单 验证脚本 if request gt hasFile photos marker gt photos request gt ph
  • 判断一个数字是否能被 3 或 5 整除 (FizzBu​​zz)

    如何根据输出是否能被 3 或 5 整除来更改输出 如果它能被 3 整除 我想显示 rock 如果它能被 5 整除 我想显示 star 类似于 FizzBu zz 如果两者都有 他们都会看到 这是我的代码 if var n Math floo
  • jQM / jquery-collagePlus 使用问题

    我正在使用 jQM 构建应用程序 并且尝试使用 jquery collagePlus http ed lea github io jquery collagePlus http ed lea github io jquery collage
  • 在 React Navigation 中将 props 传递给自定义抽屉导航器

    在反应导航抽屉菜单中 我想显示用户名 John Doe 它处于我的主要组件的状态 Router 我怎样才能将自定义抽屉内容组件传递给它 额外信息 我从 AsyncStorage 中获取此名称 组件已挂载 这是我的代码 export defa
  • 在 Fabric.js 中按宽度/高度在另一个画布对象内居中和缩放画布对象

    Goal 将一个对象 水平和垂直 置于另一个对象 矩形或组 的中心canvas via Fabric js或者通过Javascript保持原始对象的长宽比相同 但也不超过父对象的宽度 高度比例 父对象 矩形或组 不会居中于canvas元素
  • 如何检测元素内容何时发生变化

    我正在寻找一种方法来监视元素内动态填充 无页面重新加载 内容 以便我可以将类添加到另一个元素 到目前为止我有这个 HTML div class message container div class messages error span
  • 如何打开弹出窗口并用父窗口中的数据填充它?

    如何使用 JavaScript jQuery 使用父页面中 JS 变量的数据填充弹出窗口 在我的示例中 我有一个文件名数组 我在父窗口中最多列出五个 如果还有更多 我想提供一个链接来打开弹出窗口并列出数组中的每个帖子 因此 如果我打开一个包
  • 禁用特定 div 上的 Tab 键

    我有以下结构 div div Some content div div Some content div div 我想 禁用 div2 上的 tab 键 我的意思是按下 tab 键时 div2 的元素不会获得焦点 有没有简单的方法可以使用
  • 如何处理requireJs超时错误?

    我正在使用 require js 作为加载框架编写一个移动混合应用程序 我遇到加载错误的问题 我想做的是在设备离线且无法下载在屏幕上显示地图所需的 google 地图 API 脚本时设置后备解决方案 我得到的只是 Uncaught Erro
  • Knockout.js 安全绑定

    我想使用带有淘汰赛的安全绑定 为此我使用敲除安全绑定 js https github com brianmhunt knockout secure binding 谁能解释一下为什么下面的代码不起作用 它会抛出一个错误 未捕获 淘汰 安全
  • mozilla pdf.js 没有全视图

    我喜欢这个 pdf 查看器https github com mozilla pdf js https github com mozilla pdf js Demo http mozilla github com pdf js web vie
  • Node.js - 重载函数

    有没有一种方法可以重载node js中的函数 类似于 noSuchMethod https developer mozilla org en JavaScript Reference Global Objects Object noSuch
  • 使用 JQuery 根据下拉列表选择的值显示/隐藏控件

    我正在尝试使用 JQuery 根据下拉菜单的选定索引显示 隐藏 div 标签 但它不起作用 任何帮助将不胜感激 Thanks
  • Internet Explorer 9 是否会因数组和对象文字末尾的额外逗号而卡住?

    现代浏览器和 Node js 等环境允许您说 a 1 b 2 或 1 2 3 这在历史上一直是 Internet Explorer 的问题 Internet Explorer 9 中修复了此问题吗 对此有两种不同的答案 一种是对象初始值设定
  • 无法使用 HTML 设置未定义 jQuery UI 自动完成的属性“_renderItem”

    我使用以下代码将 jQuery UI 自动完成项呈现为 HTML 这些项目在自动完成控件中正确呈现 但我不断收到此 JavaScript 错误并且无法移动过去 Firefox 无法转换 JavaScript 参数 Chrome 无法设置未定

随机推荐

  • Tensorflow2.x模型搭建的几种代码形式

    相信很多新手小白在才开始初学时就想要搭建自己的深度学习模型 但在看到每个风格不同的算法时 又会把前向传播 反向传播 和模型的搭建过程混淆 我总结了一下几种基于Tensorflow2 x搭建模型的代码 1 学习过程中最常见的数据切片 载入并预
  • cpu温度过高 ubuntu_联想拯救者Y7000P温度过高?Fn+Q配合XTU做温度和功耗测试

    Y7000P温度过高 Fn Q配合XTU做温度和功耗测试 国庆节入手Y7000P 机子很稳定 但是打大型游戏温度动辄90 以上 经常撞到95 温度墙 为了降低游戏中的温度 做了以下测试 Y7000P的i5 9300H功耗墙60W 78W 温
  • ecology9 系统文件常用说明

    这里写目录标题 数据库文件 操作异构系统数据库 白名单文件 日志框架的使用 数据库文件 D WEAVER ecology WEB INF prop weaver properties 操作数据库 public static void mai
  • golang - 函数的使用

    核心化编程 为什么需要函数 代码冗余问题 不利于代码维护 函数可以解决这个问题 函数 函数 为完成某一功能的程序指令 语句 的集合 称为函数 在 Go 中 函数分为 自定义函数 自己写的 系统函数 系统提供的 函数的定义 基本语法 func
  • 基于空间平滑MUSIC算法的相干信号DOA估计(1)

    空间平滑MUSIC算法 1 1 前言 在上一篇博客中有提到 当多个入射信号相干时 传统MUSIC算法的效果就会不理想 具体原因是多个入射信号相干时 有部分能量就会散发到噪声子空间 使得MUSIC算法不能对其进行有效估计 针对这种情况 解相干
  • Qt 的网络通信(TCP)

    基于TCP Qt的网络通信 在标准 C 没有提供专门用于套接字通信的类 所以只能使用操作系统提供的基于 C 的 API 函数 基于这些 C 的 API 函数我们也可以封装自己的 C 类 但是Qt 提供了封装好的套接字通信类 QTcpServ
  • 史上超强最常用SQL语句大全

    史上超强最常用SQL语句大全 DDL Data Definition Language 数据定义语言 一 操作库 二 操作表 DML Data Manipulation Language 数据操作语言 一 增加 insert into 二
  • 性能测试调优应该注意哪些要点,一般性能测试调优的步骤-Alltesting

    性能测试调优应该注意的要点 要点1 在应用系统的设计开发过程中 应始终把性能放在考虑的范围内 要点2 确定清晰明确的性能目标是关键 要点3 必须保证调优后的程序运行正确 要点4 系统的性能更大程度上取决于良好的设计 调优技巧只是一个辅助手段
  • steam上wallpaper静态壁纸如何提取高清图

    mirrors notscuffed repkg GitCode 将壁纸资源文件打开 把sene pkg与两个文件放在同目录下在 打开终端输入 RePKG exe extract scene pkg 目录下找到 output materia
  • map reduce takeaways

    首先是数据的partition share nothing parallel architecture 执行task的machine独立 各自处理自己的partition 不需要通信 暴露给用户的控制点只有2个 map function 和
  • 基于51单片机的水箱水位监测控制系统proteus仿真原理图PCB

    功能介绍 0 本系统采用STC89C52作为单片机 1 通过传感器监测水位 当水位低于水位下限时 接通加水水泵 直到水位达到水位上限 停止加水 2 水位低于水位下限时 声光报警 3 可按键手动加水 直到水位达到水位上限 停止加水 4 采用D
  • Axure基础:母版与内联框架

    一 母版 1 母版的作用 母版是解决了我们页面中的重复元素和同步改动的问题 举个例子在两个页面中假设都有这个元素和界面 那我如果我们不用母版 用常规手段就是复制黏贴 但这样没办法保证我们数据同步问题 如果改动其中一个元件 另一个元件没办法同
  • 陀螺解读

    出品 陀螺研究院 区块链是在数字世界围绕数据的记录 组织和传播创造的共建 共享 共治的应用范式 作为一种能够满足数字经济发展需求的关键技术 区块链可有效赋能产业转型 聚力推动产业经济价值 2019年10月24日 中共中央政治局明确把区块链作
  • 马氏距离-Mahalanobis Distance

    Mahalanobis距离是表示数据的协方差距离 它是一种有效的计算两个未知样本集的相似度的方法 与欧氏距离不同的是它考虑到各种特性之间的联系 与欧氏距离不同的是它考虑到各种特性之间的联系 例如 一条关于身高的信息会带来一条关于体重的信息
  • IDEA生成JSON字符串

    第一步 先书写以下基本程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package cn lianxi cn lianxi json Author Wxz Date 2020 8 19 16 45 pu
  • UVa1614

    这道题是一道好题 我想了很久都没有想出合适的方案 这道题考了我们贪心 不确定 数学推导 确定 的能力 看来我的数学逻辑以及推理能力还需要加强啊 题意不说 直接上思路 由于1 lt ai lt i的条件 我们需要从这里入手求解 首先 我们需要
  • Vue判断字符串(或数组)中是否包含某个元素

    Vue判断字符串中是否包含某个字符串 方法有好多种 这里暂时先说我知道的两种 以后知道了别的 会继续更新 方法一 includes方法 数组 字符串都可以 var str Hello World if str includes World
  • 关于多层感知机(MLP)你必须知道的20个知识点

    问题1 MLP的基本组成单元是什么 答 MLP的基本组成单元是神经元 neuron 它通过激活函数对输入进行加权求和和非线性变换 问题2 MLP通常有几层 答 MLP通常有输入层 隐藏层和输出层 隐藏层可以有一层或多层 问题3 MLP的训练
  • 配置ntp客户端与服务器端时间的同步

    1 实验机器介绍 Ip地址 服务器1 192 168 245 128 服务器2 192 168 245 130 客户端1 192 168 245 129 实验前准备 在ntpS1 和ntpS2 中 配置外部服务器为同步服务器 并开放给192
  • 前端内存泄漏和溢出的情况以及解决办法

    写在前面 在平时写代码时 内存泄漏的情况会时有发生 虽然js有内存回收机制 但在平时编程中还是需要注意避免内存泄漏的情况 前几天做移动端时遇到一个内存泄漏造成移动端页面卡顿的问题 所以想总结下前端内存泄漏的情况 回顾下基础知识 一 什么是内