IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> js 内存泄漏 -> 正文阅读

[JavaScript知识库]js 内存泄漏

内存泄漏:当不再用到的对象内存,没有及时被回收,想要避免就让无用数据不存在引用关系。
内存膨胀:即在短时间内内存占用极速上升到达一个峰值,想要避免需要使用技术手段减少对内存的占用。
频繁GC: GC执行的特别频繁,一般出现在频繁使用大的临时变量导致新生代空间被装满的速度极快,而每次新生代装满时就会触发 GC,频繁 GC 同样会导致页面卡顿,想要避免的话就不要搞太多的临时变量,因为临时变量不用了就会被回收。

泄漏1:闭包

  • 有权访问另一个函数作用域中的变量的函数

泄漏2:隐式全局变量

  • 函数中的局部变量在函数执行结束后这些变量已经不再被需要,所以垃圾回收器会识别并释放它们。但是对于全局变量,垃圾回收器很难判断这些变量什么时候才不被需要,所以全局变量通常不会被回收
function fn(){
  // 没有声明从而制造了隐式全局变量test1
  test1 = new Array(1000).fill('isboyjc1')
  
  // 函数内部this指向window,制造了隐式全局变量test2
  this.test2 = new Array(1000).fill('isboyjc2')
}
fn()

  • 因为没有声明和函数中this的问题造成了两个额外的隐式全局变量,这两个变量不会被回收

泄漏3:DOM引用

<div id="root">
  <ul id="ul">
    <li></li>
    <li></li>
    <li id="li3"></li>
    <li></li>
  </ul>
</div>
<script>
  let root = document.querySelector('#root')
  let ul = document.querySelector('#ul')
  let li3 = document.querySelector('#li3')
  
  // 由于ul变量存在,整个ul及其子元素都不能GC
  root.removeChild(ul)
  
  // 虽置空了ul变量,但由于li3变量引用ul的子节点,所以ul元素依然不能被GC
  ul = null
  
  // 已无变量引用,此时可以GC
  li3 = null
</script>


在这里插入图片描述

泄漏4:定时器

  • 当不需要 interval 或者 timeout 时,最好调用 clearInterval 或者 clearTimeout来清除,另外,浏览器中的 requestAnimationFrame 也存在这个问题,我们需要在不需要的时候用 cancelAnimationFrame API 来取消使用

泄漏5:事件监听

<template>
  <div></div>
</template>

<script>
export default {
  created() {
    window.addEventListener("resize", this.doSomething)
  },
  beforeDestroy(){
    window.removeEventListener("resize", this.doSomething)
  },
  methods: {
    doSomething() {
      // do something
    }
  }
}
</script>

泄漏6:事件的监听发布

<template>
  <div></div>
</template>

<script>
export default {
  created() {
    eventBus.on("test", this.doSomething)
  },
  beforeDestroy(){
    eventBus.off("test", this.doSomething)
  },
  methods: {
    doSomething() {
      // do something
    }
  }
}
</script>

  • 当实现了监听者模式并收集了相关的事件处理函数,其中引用的变量或者函数都被认为是需要的而不会进行回收

泄漏7:Map、Set强引用

let obj = {id: 1}
let user = {info: obj}
let set = new Set([obj])
let map = new Map([[obj, 'hahaha']])

// 重写obj
obj = null 

//以下强引用,并不会因为垃圾回收掉
console.log(user.info) // {id: 1}
console.log(set)
console.log(map)

map.delete(obj);		
obj = null;	//此时才能去除map对key所引用对象的强引用


let weakSet = new WeakSet([obj])
let weakMap = new WeakMap([[obj, 'hahaha']])

// 重写obj引用
obj = null
// {id: 1} 将在下一次 GC 中从内存中删除

泄露8:未清理的console

  • 之所以在控制台能看到数据输出,是因为浏览器保存了我们输出对象的信息数据引用,也正是因此未清理的 console 如果输出了对象也会造成内存泄漏

内存泄漏定位
在这里插入图片描述

  • 先点击6手动进行一次垃圾回收,4、5都点上,然后点击1开始录制
    在这里插入图片描述
  • 可以看到快照对应下的内存曲线,如果在手动执行垃圾回收后,曲线并没有明显下降,说明可能存在内存泄漏
  • 点击Memory,可以为我们提供更多详细信息,比如记录 JS CPU 执行时间细节、显示 JS 对象和相关的DOM节点的内存消耗、记录内存的分配细节等
  • 其中的 Heap Profiling 可以记录当前的堆内存 heap 的快照,并生成对象的描述文件,该描述文件给出了当下 JS 运行所用的所有对象,以及这些对象所占用的内存大小、引用的层级关系等等,用它就可以定位出引起问题的具体原因以及位置。
    在这里插入图片描述
  • 先手动点击垃圾回收,然后操作页面,然后点击1生成快照,循环操作几次
    在这里插入图片描述
Summary:按照构造函数进行分组,捕获对象和其使用内存的情况,可理解为一个内存摘要,用于跟踪定位DOM节点的内存泄漏
Comparison:对比某个操作前后的内存快照区别,分析操作前后内存释放情况等,便于确认内存是否存在泄漏及造成原因
Containment:探测堆的具体内容,提供一个视图来查看对象结构,有助分析对象引用情况,可分析闭包及更深层次的对象分析
Statistics:统计视图

在这里插入图片描述

Constructor:显示所有的构造函数,点击每一个构造函数可以查看由该构造函数创建的所有对象
Distance:显示通过最短的节点路径到根节点的距离,引用层级
Shallow Size:显示对象所占内存,不包含内部引用的其他对象所占的内存
Retained Size:显示对象所占的总内存,包含内部引用的其他对象所占的内存

//Constructor这一列
system、system/Context 表示引擎自己创建的以及上下文创建的一些引用,这些不用太关注,不重要
closure 表示一些函数闭包中的对象引用
array、string、number、regexp 这一系列也能看出,就是引用了数组、字符串、数字或正则表达式的对象类型
HTMLDivElement、HTMLAnchorElement、DocumentFragment等等这些其实就是你的代码中对元素的引用或者指定的 DOM 对象引用
  • 选择Comparison比较,或者右侧的filter
    在这里插入图片描述在这里插入图片描述

New:新建了多少个对象
Deleted:回收了多少个对象
Delta:新建的对象数 减去 回收的对象数

  • 需要重点关注 Delta ,只要它是正数就可能存在问题

在这里插入图片描述

  • closure 上面也说过代表闭包引用,可以查看到代码中发生引用的位置
  • 根据其他的如Array等构造函数的Distance层级也能定位发生泄漏的位置
  • 如上就能定位两个问题,一是代码 30 行的闭包引用数组造成的内存泄漏,二是数组的元素不断增多造成的内存泄漏。
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-14 22:29:05  更:2022-06-14 22:31:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:46:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码