垃圾回收

79 阅读2分钟

这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

  • 由于考虑到内存性能问题,当我们不再需要某些内容时就要用Javacript引擎清理

可达性

  • 这是JavaScript管理内存的概念

"可达"值:以某种形式可访问或可用的值,一定是存储在内存中的

0. 固有可达值不能被释放

  • 当前执行的函数及相关调用链的局部变量和参数
  • 全局变量
  • 还有一些其他的,内部的。

这些值被称作——

1. 判断值的可达

  • 一个值可以通过引用链从根访问任何其它值
  • 这里举个例子:
// user 具有对这个对象的引用
let user = {
  name: "John"
};

上面的代码:user是全局变量,它引用了对象{name:"John"},这时候它是可达的

但是加上这句user = null ,对象{name:"John"}变成不可达的了,原因是没有了引用 。这时候垃圾回收器(在 JavaScript 引擎中有一个被称作 垃圾回收器 的东西在后台执行。)就认为它是垃圾数据进行回收,再释放内存

  • 改变下思路,这里将user = null 换成let admin = user,这时候就是两个引用 image.png

只有将user和admin都重写成null才会被回收

  • 相互关联的对象

现在来看一个更复杂的例子。这是个家庭:

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  }
}

let family = marry({
  name: "John"
}, {
  name: "Ann"
});

代码的结构如图所示

image.png

这时移除两个引用:

delete family.father;
delete family.mother.husband;

变成

image.png

这里还是可达,实际应该将delete family.mother.husband 改为delete family.father.wife。因为,对外传入的引用对可达无影响,对内传入才有效

image.png

  • 极端状况

上面的代码重写为family = null

这时

image.png

由此可见,几个对象相互引用,但外部没有对其任意对象的引用,这些对象也可能是不可达的,并被从内存中删除。

内部算法(mark-and-sweep)

  • 假设有对象如下,

image.png

垃圾回收步骤:

  1. 垃圾收集器找到所有的根,并“标记”(记住)它们。
  2. 一层层遍历它们相关的引用标记,直到所有可达的(从根部)引用都被访问到。
  3. 没有被标记的对象都会被删除。

image.png