JS-垃圾清理机制

JavaScript 中的内存管理对我们来说是自动且不可见的。我们创建基元、对象、函数……所有这些都需要内存。

当不再需要某些东西时会发生什么?JavaScript 引擎如何发现并清理它?

可达性

JavaScript 内存管理的主要概念是可达性。

简而言之,“可达”值是以某种方式可访问或可引用的值。它们保证存储在内存中。

  1. 有一组固有的可访问值,由于显而易见的原因不能删除。例如:

    • 当前执行的函数,它的局部变量和参数。
    • 当前嵌套调用链上的其他函数、它们的局部变量和参数。
    • 全局变量
    • 其他内部数据

这些值称为 root (根)。

  1. 如果可以通过引用或引用链从根访问任何其他值,则认为它是可访问的。

例如,如果全局变量中有一个对象,并且该对象具有引用另一个对象的属性,则该对象被认为是可达的。它引用的那些也是可以访问的。

JavaScript 引擎中有一个后台进程,称为垃圾收集器。它监视所有对象并删除那些变得无法访问的对象。

内部算法

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

定期执行以下“垃圾收集”步骤:

  • 垃圾收集器爬取并“标记”它们。
  • 然后它访问并“标记”来自它们的所有引用
  • 然后它访问标记的对象并标记它们的引用。所有访问过的对象都会被记住,以免以后访问同一个对象两次。
  • ...依此类推,直到访问每个可访问的(从根)引用。
  • 除标记对象外的所有对象(或者无法访问的整个互连对象)都将被删除

这就是垃圾收集如何工作的概念。JavaScript 引擎应用了许多优化以使其运行更快且不影响执行。一些优化:

  • 分代集合——对象被分成两组:“新的”和“旧的”。许多物体出现,完成它们的工作并快速死亡,它们可以被积极地清理。那些活得足够长的人会变“老”,并且检查频率较低。

  • 增量收集- 如果有很多对象,并且我们尝试一次遍历并标记整个对象集,则可能需要一些时间并在执行中引入明显的延迟。因此引擎尝试将垃圾收集拆分为多个部分。然后这些部分一个一个地分别执行。这需要它们之间进行一些额外的簿记以跟踪更改,但是我们有许多微小的延迟而不是大的延迟。

  • 空闲时间收集——垃圾收集器尝试仅在 CPU 空闲时运行,以减少对执行的可能影响。

垃圾收集算法存在其他优化和风格,不同的引擎实现了不同的调整和技术。

总结

  1. 垃圾收集是自动执行的。我们不能强迫或阻止它。
  2. 对象在被引用与可访问时保留在内存中。
  3. 被引用对象从根上可访问对象不同:被引用的一组相互关联的对象作为一个整体可能变得不可访问。

参考资料