JavaScript 垃圾回收机制

前言

我们知道,JavaScript 中的变量分为两种:基本类型和引用类型。基本类型的值存储在栈内存,引用类型的值存储于栈内存和堆内存,栈内存中保存的是堆内存地址,地址指向堆内存中保存着的具体的值。栈内存中的变量值使用完之后会自动出栈被立即回收,但是堆内存中的值则需要某种策略或手动回收。
JavaScript 自带一套内存管理引擎来进行内存分配以及垃圾回收,那么为了更好的开发和维护高性能的 JavaScript 代码,我们需要对垃圾回收机制进行一些了解。
下面我们从以下几个方面来了解垃圾回收机制

  • 什么是垃圾回收
  • 垃圾是怎么产生的
  • 垃圾回收机制

什么是垃圾回收

垃圾回收机制的原理即找到不再使用的变量,释放其内存,因此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这已操作。

垃圾是怎么产生的

当一个对象没有任何变量或属性对它进行引用时,意味着我们无法在操作该对象了,这种对象就是所谓的"垃圾",此时就需要进行垃圾回收,如果不进行清理,内存占用越来越高,就会影响性能,甚至会导致进程崩溃。
比如:

let obj = [ 'a', 'b', 'c' ]
obj = {
  name: 'abc'
}

在 JavaScript 中,引用类型的数据保留在堆内存中,栈内存中会保留一个地址,这个地址即为堆内存中保存的值。
上面先声明了一个变量,为一个数组,之后,我们把这个变量重新赋值,那么之前的引用关系就没有了,此时,之前的那个数组就会失去引用关系,也就是我们无法在操作它了,它就变成了 “垃圾”,等待被回收。

垃圾回收机制

最常见的垃圾回收机制有两种:

  1. 标记清除
  2. 引用计数

标记清除(Mark-Sweep)

标记清除,简单来说,就是使用某种方法,将不再使用的变量,也就是无用变量标记出来,等待垃圾收集器回收,释放内存。
那么,垃圾收集器是如何标记无用变量呢,这里,我们先了解一个概念——可达性。

可达性

可达性,指的是变量从"根"出发,经过一层或多层可以被访问到。即一个变量从"根"出发,可以被访问到,那么它就是"可达"的,垃圾回收器将这些"可达"的变量视为有用变量,反之则视为无用变量,无用变量会被打上标记,便于之后回收。
在 JavaScript 中,有一些基本的固有可达值,如:

  1. 本地函数的局部变量和参数
  2. 当前嵌套调用链上的其他函数的变量和参数
  3. 全局变量
  4. 一些其他的内部的值

举一个简单的例子:

let user = {
  name: 'Avery'
}

可达性.png

这里是一个全局变量 user 引用了对象,当我们把 user 重写,那么这个引用就没有了,没有了引用就变成了不可达的,就会被回收
不可达.png

了解了可达性,我们就来看下垃圾回收器是如何进行标记的吧,各个浏览器的具体实现不太相同,其运行机制如下:

  • 变量进入上下文,会被加上标记,证明其存在于该上下文
  • 将所有在上下文的变量以及上下文中被访问引用的变量标记去掉,表明这些变量活跃
  • 之后再被加上标记的变量为准备删除的变量,因为上下文中已访问不到它们了
  • 执行内存清理,销毁所有带标记的非活跃值并收回之前被占用的内存

标记清除有一个缺点就是-内存碎片,因为标记清除,在清除之后,剩余内存的位置是不变的,所以会导致空闲的内存空间是不连续的,大小不同的碎片。
想要解决这个缺点,就需要标记整理,它会在标记结束后,将不需要清理的对象移至内存的一端,最后清理掉边界的内存。

引用计数(Reference Counting)

引用计数,把"对象是否不再需要"简化定义为"对象有没有其他对象引用到它",即该对象没有被任何对象或变量引用(零引用),就会被垃圾回收机制回收,其运行机制如下:

  • 当声明了一个变量,并赋予它一个引用的值时,该值的引用次数 +1
  • 当同一个值被赋值给另一个变量的时候,引用次数 +1
  • 当该变量被另一个值覆盖的时候,引用次数 -1
  • 当引用次数为 0 的时候,就会被内存回收

引用计数有一个最大的问题,就是循环引用,如下:

function test () {
  let a = {}
  let b = {}
  a.c = b
  b.c = a
}

如上,两个都互相引用了,引用计数不为 0 ,所以无法被回收,这样就会造成内存泄漏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值