JavaScript 垃圾回收入门(复盘校对版)

💡 原文中文,约2800字,阅读约需7分钟。
📝

内容提要

JavaScript垃圾回收机制的核心概念是“可触及”:从根(全局变量、当前函数局部变量等)出发能被引用到的值会保留在内存,否则被回收。相互引用但整体与根断开的“孤岛”也会被清除。常用算法为标记-清除:从根标记所有可达对象,未标记的删除。引擎还采用分代、增量、闲时收集等优化提升效率。

🔎

延伸解读

理解“可触及”是排查内存问题的关键

文章强调,JavaScript 内存管理的关键概念是“可触及”。从根(全局变量、当前函数局部变量等)出发能被引用到的值会保留,否则被回收。这意味着,即使对象之间相互引用,只要整体与根断开,也会被清除。因此,当遇到内存泄漏时,应检查是否有意外的全局变量或闭包导致对象仍可触及。

标记-清除算法与引擎优化

基础垃圾回收算法是标记-清除:从根开始标记所有可达对象,未标记的删除。现代引擎还采用分代收集、增量收集和闲时收集等优化。分代收集将对象分为新生代和老生代,频繁清理新生代;增量收集将标记过程分片以降低延迟;闲时收集在 CPU 空闲时运行。这些优化提升了效率,但具体实现因引擎而异。

相互引用与孤岛:为何引用不等于可触及

文章通过示例说明,相互引用的对象可能整体不可触及。例如,两个对象互相引用,但若没有从根到它们的引用链,它们就形成“孤岛”,会被回收。这澄清了常见误解:引用关系本身不保证对象存活,必须从根可达。因此,在管理复杂对象关系时,需注意切断与根的连接。

❓

Q&A

JavaScript 垃圾回收中的“可触及”是什么意思?

“可触及”是 JavaScript 内存管理的关键概念,指从根(root)出发通过引用链能够访问到的值。这些值会被保留在内存中,而不可触及的值会被垃圾回收机制删除。

哪些值在 JavaScript 中会被视为根(root)?

根包括:当前函数的局部变量和参数、当前调用链中所有函数的局部变量和参数、全局变量,以及其他内部变量。这些值无论如何都不能被删除。

相互引用的对象是否一定不会被垃圾回收?

不一定。如果相互引用的对象整体与根断开连接,形成“孤岛”,那么即使它们之间互相引用,也会因为不可触及而被垃圾回收。

标记-清除算法是如何工作的?

标记-清除算法从根开始标记所有可达对象,然后访问并标记它们的引用,如此递归,直到没有未访问的引用。最后,所有未被标记的对象都会被移除。

JavaScript 引擎有哪些常见的垃圾回收优化策略?

常见优化包括:分代收集(将对象分为新生代和老生代,频繁清理新生代)、增量收集(将标记过程分割成多份以降低延迟)、闲时收集(尽量在 CPU 空闲时运行垃圾回收)。

我们能否手动强制或阻止 JavaScript 的垃圾回收?

不能。垃圾回收是自动进行的,我们无法强制或阻止其运行。

🏷️

标签

➡️

继续阅读