JavaScript中的垃圾回收(GC)?


JavaScript 的内存管理比 C 或 C++ 等低级语言容易得多。与低级语言不同,JavaScript 会自动检测哪些对象在以后会用到,哪些对象是无用的垃圾,它们占据内存却没有理由。在本文中,我们将讨论 JavaScript 中的垃圾回收 (GC) 如何工作。我们将详细讨论一些重要的部分:

  • 从根的可达性

  • 互联对象(不同对象之间的互连)

  • 不可达集合(断开的链接)

可达性

内存管理的第一个概念是可达性。在这种模式下,垃圾收集器尝试从某个点搜索可达的值。当某个值或内存位置从某个点可达时,它将不会被移除。对象可以直接或间接地从某个位置到达。有一些方法可以确定对象是否可达:

  • 当函数当前正在执行时,其局部变量和参数可以直接访问。

  • 如果可以从当前正在执行的函数调用其他函数,这些函数也可以访问。不仅是该函数,链中这些函数的参数和局部变量也将可访问。

  • 全局变量始终可访问

这些直接可访问的对象称为根对象。当从根可访问的其他值也被标记为可访问时。例如,假设我们有一个对象 ob1 作为我们的全局对象。由于 ob1 是全局的,它是根。现在 ob1 中还有一个引用指向 ob2。第二个对象 ob2 并非直接可访问,但它可以通过根对象 ob1 访问。因此,它也将被标记为可访问。当某个对象变得不可访问时,一个名为垃圾收集器的后台低优先级进程将这些不可访问的对象从内存中清除。

示例

使用代码和一些图表显示了上述思想。

代码

let company = { name: "Tutorialspoint" };


该图描述了一个公司对象指向一个存储名为“Tutorialspoint”的字符串变量的对象。现在这个对象可以通过名为“company”的引用访问。此时,如果我们将 company 设置为 **null**,则引用将丢失。

代码

company = null;


设置 company = null 后,该对象不可访问。因此,垃圾收集器将在其轮到时移除这部分。

让我们来看另一个示例,我们在这里使用两个引用。让我们考虑以下代码,其中 company 对象由另一个名为 ob 的变量引用。

代码

let company = { name: "Tutorialspoint" }; let ob = company;

然后,如果我们设置 company = null,状态将如下所示:

因此,该对象由另一个名为“ob”的链接引用。换句话说,该对象可以通过“ob”访问。这就是为什么垃圾收集器不会将其从内存中移除的原因。

互联对象

Javascript 对象可以与多个对象链接在一起。或者我们可以说它们可以与一些类似的对象互连。在这种情况下,结构变得更加复杂。让我们来看一个例子来理解互联对象。

示例

代码

function parent(dad, daughter) { dad.daughter = daughter; daughter.dad = dad; return { father: dad, child: daughter } } let parent = parent({ name: "Bob" }, { name: "Alice" });

此示例显示 parent() 函数创建了两个对象 father 和 child,名称分别为“Bob”和“Alice”,这两个对象通过“dad”和“daughter”关系相互关联。在下图中,我们可以直观地看到这种情况。它表明这两个对象是互连的。

此时,如果我们删除一些连接,例如:

代码

delete parent_child.father delete parent_child.child.dad


删除这两个链接后,father(Bob)没有传入链接。垃圾收集器将从内存中移除整个 father 对象。此想法在下图中进行了描述。

不可达岛

第三种情况可能是不可达岛。考虑上一节(互联对象)中显示的相同示例。现在,如果我们删除父对象的链接,它将分离整个对象,如下面的图表所示:


父链接已删除,因此整个对象以及 father 和 child 对象都不可访问。它们形成了一个不可达岛。

代码

parent = null;

结论

与任何其他语言一样,内存管理是一项非常重要的任务,最重要的是,清除未使用的内存块对于编写更好、更高效的代码是必要的。JavaScript 自动收集无用内存块的信息并将其从内存中移除。垃圾收集器搜索从根对象的可达性以确定对象将来是否会被使用。对于互联对象,它会搜索对象是否没有传入边,则该对象无法访问,因此它会将该对象从内存中移除。

更新于:2022年8月22日

2K+ 次查看

启动您的 职业生涯

通过完成课程获得认证

开始
广告