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的例子。
相关推荐
Martin -Tang19 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发20 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html