JS笔记之JS对象基础知识(三)

1 垃圾回收

对于开发者来说,JavaScript 的内存管理是自动的、无形的。我们创建的原始值、对象、函数……这一切都会占用内存。

1.1 什么是垃圾?

在JS引擎运行时,我们创建的一些原始值、对象,经过使用之后就没有就再也没有使用过,这些个原始值,或者对象都是垃圾。

1.2 有哪些垃圾?

任何变量或者对象在未来的程序运行中总不会被访问的b变量和对象都是垃圾。

1.3 什么是垃圾回收?

JS对内存管理的一种手段。

1.4 为什么垃圾回收?

释放内存,节约资源。

1.5 如何垃圾回收?

JS中的内存管理概念可达性,就是能够通过某种凡是访问到的值,他们一定是存在于内存中的。

比如一些明显的可达的值:

  • 当前执行的函数,他的局部变量和参数。
  • 当前嵌套调用链上的其他的函数,他们的局部变量和函数。
  • 全局变量
  • 一些内部的对象

一个值可以通过引用链从根访问任何其他值,则认为该值也是可达的。

一个例子:

1
2
3
4
// user 具有对这个对象的引用
let user = {
name: "John"
};

image-20230117154427386

user 指的的时这个 Object的对象的引用,全局变量 "user" 引用了对象 {name:"John"}

如果 user 被重写,赋予了其他的值,那么这个引用就没了,

image-20230117155148312

现在这个 Object 变成不可达的了,垃圾收集器就会将它视为垃圾,然后进行回收。

垃圾回收的内部算法:

  1. 垃圾收集器找到所有的根并标记它们。
  2. 然后它遍历并标记来自它的引用。
  3. 然后他遍历标记的对象并标记它们额的引用,所有被遍历到的对象都会被记住,以免将来再次遍历到同一个对象。
  4. 循环操作直到所有可达的对象都被访问到并标记。
  5. 没有被标记的测会被删除。

JS 引擎对垃圾回收做了优化,使垃圾回收运行速度更快,并且不会对代码执行引入任何延迟。

1.6 一些优化建议:

  • 分代收集(Generational collection)—— 对象被分成两组:“新的”和“旧的”。在典型的代码中,许多对象的生命周期都很短:它们出现、完成它们的工作并很快死去,因此在这种情况下跟踪新对象并将其从内存中清除是有意义的。那些长期存活的对象会变得“老旧”,并且被检查的频次也会降低。
  • 增量收集(Incremental collection)—— 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟。因此,引擎将现有的整个对象集拆分为多个部分,然后将这些部分逐一清除。这样就会有很多小型的垃圾收集,而不是一个大型的。这需要它们之间有额外的标记来追踪变化,但是这样会带来许多微小的延迟而不是一个大的延迟。
  • 闲时收集(Idle-time collection)—— 垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。