浅析JS垃圾回收

我心飞翔 分类:javascript

当我们创建对象、函数这些东西的时候,我们都需要一个内存去储存他们,即JS的内存管理其实是自动进行的,但是如果我们不需要这些东西的时候,JS是怎么知道的呢?又是怎么清理它们的呢?

JS中内存管理的主要概念是可达性(reachability),可达值是指保证那些可以被访问或者使用的值保存在内存中。比如一些固有值(roots)和可以通过引用和引用链从根访问到的值。那么这些可达值就无法被删除,剩下的其他值,就受到JS引擎中垃圾收集器的监视并删除。

举个例子:

let user = {
  name: "John"
};
 

此时全局变量user引用该对象{name: "John"}。该对象的属性存储一个基元,因此将其绘制在对象内部。可是如果这个user被覆盖user = null;,那么这个引用就丢失了,即John变得不可达,没有对象能够访问他,也没有引用他,因此垃圾收集器就会将这个数据删除。

现在我们将引用从复制useradmin

let user = {
  name: "John"
};

let admin = user;
 

当我们再次执行user = null;时,该对象虽然值为null,但是我们仍然可以通过admin全局变量访问,因此它还在内存中。可是如果我们也覆盖admin,它就会被删除了。

再来个复杂的例子:

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

  return {
    father: man,
    mother: woman
  }
}

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

此时所有的对象都是可达的,但是我们现在要做的是删除family.father这个引用,此时John还是可达的,那我们删除family.mother.husband这个引用呢?答案还是一样,可是如果我们将它们都删除呢?那么此时John就只有传出的引用,没有传入的引用,说得通俗一些就是你认识你的偶像,可是你的偶像却不认识你,这个时候你只能被无情的删除了。

同样的代码,我们执行family = null;会怎么样呢?此时就要引入一个概念即可达性概念,虽然家庭成员之间相互间都有传出和传入的引用,但是此时family对象已经和根断开了,那么John和Ann以及他们之间的相互引用链接,都会被删除。

说完概念,具体垃圾回收是怎么执行的呢?

基本的垃圾收集算法称为“标记清除”。

它定期执行以下步骤:

  1. 垃圾收集器收取他们的根并对其进行“标记”。
  2. 访问并“标记”所有来自它们的引用。
  3. 访问标记的对象以及标记它们的引用。记住所有访问过的对象,以免将来再次访问同一对象。
  4. 依此类推,直到访问了所有可到达的引用(从根开始)。
  5. 把除了被标记以外的所有对象删除。

这就是垃圾收集工作原理的概念。

注意
  • 垃圾收集是自动执行的。我们不能强迫或阻止它。
  • 当对象可以访问时,它们会保留在内存中。
  • 被引用与可(从根)访问不同:一堆相互链接的对象可能都不可访问。

文章来源在这

感谢观看哟

回复

我来回复
  • 暂无回复内容