JavaScript - 垃圾回收

最近在重新回顾JavaScript基础,今天是「垃圾回收」!

我们知道,当我们创建原始值、对象、函数等等数据时,都会占用内存,那当我们不再需要某个东西时会发生什么呢,JavaScript引擎是如何发现并清理它的呢?

可达性(Reachability)

JavaScript中一个主要的内存管理概念就是 可达性。"可达"值指的是那些以某种方式可以访问或者可用的值,它们一定是存储在内存之中的。

1.一些不能被释放的值:

当前执行函数的局部变量和参数;

1)当前嵌套调用链上的其他函数的局部变量和参数;

2)所有的全局变量;

以上这些值被称作

2.什么样的值会被视为"可达"呢?

如果全局变量中有一个对象,并且这个对象有一个属性引用了另一个对象,那么"另一个"对象被认为是可达的,包括它引用的内容也是可达的。

一个例子:

js 复制代码
// user 具有对这个对象的引用
let user = { name: "John" };

这个箭头描述了一个对象的引用,全局变量user引用了对象{ name: "John" },这个John的"name"属性存储一个原始值。现在我们将user进行重写:

js 复制代码
user = null;

那么现在John就变成不可达的了,因为它失去了引用不能被访问了,垃圾回收器就会认为它是垃圾数据并进行垃圾回收,释放内存。这也就是 垃圾回收机制

两个引用

我们现在将user引用复制给admin,再将user赋值为null,又会发生什么呢?

js 复制代码
let user = { name: "John" };
let admin = user;
user = null;

事实上就是{ name: "John" }是仍然可以通过admin这个全局变量被访问到的,所以这个对象必须被保留在内存中。如果我们将admin也赋值null,那么{ name: "John" }对象也会被删除。

相互关联的两个对象

下面的例子展示了一个家庭,通过marry函数使两个对象之间相互引用产生了关联关系:

js 复制代码
function marry(man, woman) {
    woman.husband = man;
    man.wife = woman;
    
    return {
        father: man,
        mother: woman
    }
}

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

他们的内存结构应该是这样的,所有对象都是可达的:

现在我们移除两个引用:

js 复制代码
delete family.father;
detete family.mother.husband;

这时我们发现 {name: "Jhon"} 对象依旧可以通过 man.wife = woman 实现可达。但是如果我们将man.wife = woman 也置空,那么我们就会发现没有对Jhon的引用了。

所以现在Jhon是不可达的,就会从内存中被删除,同时Jhon的所有数据也会变得不可达。经过垃圾回收以后,现在对象变成了这样:

无法到达的岛屿

如果我们直接将family赋值为null,虽然Jhon和Ann依旧有着关联关系,但他们已经不与相连,那么他们就变成了一座"孤岛",他们会被从内存中删除。

js 复制代码
family = null;

内部算法

垃圾回收的基本算法被称为"mark-and-sweep"。

定期执行以下"垃圾回收"的步骤:

1)垃圾收集器找到所有的根,并"标记"它们;

2)然后它遍历并"标记"所有来自它们的引用;

3)然后它遍历标记的对象并标记 它们的 引用。这样所有被遍历到的对象都会被记住;

4)一直遍历下去,直到所有可达的引用都被访问到;

5)没有被标记的对象就会被删除。

比如当前的数据结构是这样的:

我们可以看到右侧现在有一个"孤岛",那么垃圾回收会怎样处理它呢?

第一步:标记所有的根

第二步:标记遍历出来的它们的所有引用的对象

如果还有引用的话,就继续标记

当所有的对象都标记完成后,就会发现右侧"孤岛"不可达,就会将它删除。

这就是垃圾回收,JavaScript引擎做了许多优化,可以使垃圾回收运行速度更快,也不会对代码执行引入任何延迟。这里暂时不说啦!

总结

  • 垃圾回收是自动完成的,我们并不能强制执行或阻止执行
  • 当对象是可达状态时,它一定是存于内存之中的
  • 被引用和可访问是不同的,被引用的对象可能存在整体都不可达,比如上面的family赋值为null的例子。
相关推荐
时清云23 分钟前
【算法】合并两个有序链表
前端·算法·面试
小爱丨同学31 分钟前
宏队列和微队列
前端·javascript
沉登c1 小时前
Javascript客户端时间与服务器时间
服务器·javascript
持久的棒棒君1 小时前
ElementUI 2.x 输入框回车后在调用接口进行远程搜索功能
前端·javascript·elementui
2401_857297911 小时前
秋招内推2025-招联金融
java·前端·算法·金融·求职招聘
undefined&&懒洋洋2 小时前
Web和UE5像素流送、通信教程
前端·ue5
大前端爱好者4 小时前
React 19 新特性详解
前端
小程xy4 小时前
react 知识点汇总(非常全面)
前端·javascript·react.js
随云6324 小时前
WebGL编程指南之着色器语言GLSL ES(入门GLSL ES这篇就够了)
前端·webgl
随云6324 小时前
WebGL编程指南之进入三维世界
前端·webgl