【前端进阶】js的内存管理

目录

前言

一、内存生命周期

二、内存的分配和使用

1. 内存空间

 2. 变量的存放和使用

 三、垃圾回收

1、引用

 2、标记

四、内存泄露

五、避免内存泄露

六、参考: 


前言

随着对js的理解逐渐加深,今天主要分享一下个人对内存的理解、风险和优化。


一、内存生命周期

  1. 分配内存:把变量、函数等分配到对应的内存空间
  2. 内存使用:使用变量、函数等,也就是读写内存
  3. 内存回收:回收变量、函数等

二、内存的分配和使用

1. 内存空间

在了解内存的分配前,需要先了解内存的空间结构。

js的内存空间分为堆与栈

  1. 栈内存:结构特点是后进先出
  2. 堆内存:结构类似于书架,通过key-value的形式读取

 2. 变量的存放和使用

js中,变量分为了基本数据类型和引用数据类型

  1. 基本数据类型:保存在栈内存中,有固定的内存大小,通过值访问,主要有数字、字符串、布尔。
  2. 引用数据类型:保存在堆内存中,没有固定的内存大小,通过内存地址访问,主要有数组、对象、函数。

基本数据类型和引用数据类型的区别:

  1. 基本数据类型保存在栈内存中,引用数据类型保存在堆内存中。
  2. 变量保存的内容不同:基本数据类型在赋值时,是直接把数据值赋值给变量,而引用数据类型则是把在堆内存的地址赋值给变量,就比如你跟朋友分享某个网站一样,分享的只是一个连接,并不是里面的内容,所以,当一个变量改变了内存地址中的某一个值时,使用了同一个内存地址的变量中的某个值也会发生变化。 
// 基本数据类型
// 基本数据类型在赋值时的步骤:
// 1. 在栈内存中开辟一个变量的空间
// 2. 把基本数据类型的值赋值个变量
const a = 123
// 把a的值赋值给b
let b = a
b = 444
console.log(a, b) // 123 444
const c = 123
// 基本数据类型之间比较的是值
console.log(a == c) // true



// 引用数据类型
// 引用数据类型在赋值时的步骤:
// 1. 在堆内存中开辟一个空间
// 2. 在空间中存放引用数据类型
// 3. 在栈内存中开辟一个空间存放变量
// 4. 把堆内存中的空间地址赋值给变量
const aa = {
    name: '张三'
}
// 把c中保存的地址值赋值给d
const bb = aa
bb.name = '李四'
console.log(aa, bb) // {name: '李四'} {name: '李四'}
const cc = {
    name: '李四'
}
// 引用数据类型之间比较的是内存地址值
console.log(bb == cc) // false

 三、垃圾回收

垃圾回收分为:引用和标记两种机制

1、引用

引用的回收算法主要依赖于引用的概念,对象如果没有被引用,那么就回收,如果有引用,那么就不回收。

// 对象被变量o引用
let o = {
    a: 1
}
// 清除对象的引用
o = null

缺陷:循环引用时就不会被回收,如下,对象o和对象o2都不会被回收

function fn() {
    const o = {}
    const o2 = {}
    o.a = o2 // o中a属性引用o2
    o2.a = o // o2中a属性引用o
}

fn()

 2、标记

标记的回收算法主要是把对象引用到根对象的属性上,然后定期的使用跟对象上的属性,判断属性是否还存在对象的引用,如果没有就回收该对象,否则不回收,这样就解决了循环的问题。

缺陷:无法从跟对象查询到的对象都将被清除

// 未声明的变量会直接挂载到window上,也就是根对象
// 在没有清除对象的引用时,对象就不会被回收
function fn1() {
    a = {}
}

fn1()
console.log(a) // {}

// 没有挂在到根对象时,就会被回收
function fn2() {
  const aa = {}
}

fn2()
console.log(aa) // 报错

四、内存泄露

内存泄露就是变量、对象、函数等一直得不到回收,就会一直占用内存空间,达到一定数量时就会出现内存泄露。

有可能造成内存泄露方式:

  1. 未声明的变量或者意外的全局变量

  2.  DOM元素的不恰当处理:DOM元素被删除后,仍然有变量引用该DOM,导致无法被回收,需要将引用DOM的变量赋值为null

  3. 被遗忘的计时器或回调函数:定时器手动清除后还需要将变量赋值为null

  4. 闭包:内层函数会引用外层函数的变量,会导致无法回收,需要将对内层函数的引用设置为null 

  5. 死循环

五、避免内存泄露

原则:不用的东西及时清除

  1. 减少不必要的全局变量,建议使用const、let声明变量
  2. 在使用完数据后及时解除引用
  3. 避免死循环

六、参考: 

内存管理 - JavaScript | MDN

「前端进阶」JS中的内存管理 - 掘金

JS内存空间 | Suifeng

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值