一文带你轻松了解浏览器的垃圾回收机制

10 阅读3分钟

GC 垃圾回收机制

本文为文章《「硬核JS」你真的了解垃圾回收机制吗?》学习笔记,在阅读前强烈建议阅读此文章。

什么是GC?

GCGarbage Collection,程序在工作过程中会产生很多垃圾,这些垃圾是程序不再使用的空间。GC的作用就是负责回收这些空间。

垃圾是如何产生的?

  1. 内存分配:当执行JavaScript代码时,V8引擎会在内存中为各种对象(如数组、字符串、对象字面量等)分配空间。
  2. 垃圾产生:在JavaScript程序中,变量和对象的引用关系会随着程序的执行而不断变化。当某个对象不再被任何变量或对象引用时,它所占用的内存空间就变成了“垃圾”。

如何找出垃圾?

目前,主流的垃圾回收算法包括两种:

  1. 标记清除算法(Mark-and-Sweep):

    • 标记阶段:从根集合(如全局对象)开始,遍历所有可达的对象,并标记它们为“已引用”。
    • 清除阶段:遍历堆中的所有对象,将未被标记为“已引用”的对象视为垃圾,并回收它们所占用的内存。
  2. 引用计数算法(Reference Counting):

    • 每个对象维护一个引用计数器,每当有一个新的引用指向它时,计数器加1;每当一个引用离开作用域或被设置为null时,计数器减1。
    • 当对象的引用计数器为0时,表示没有任何引用指向它,因此可以安全地回收其内存。

    注意:虽然引用计数算法实现简单,但它存在循环引用的问题,即两个对象相互引用,但不再被外部引用,导致它们无法被回收。因此,现代JavaScript引擎(如V8)主要采用标记清除算法。

如何清除垃圾?

V8引擎将堆内存分为两个主要区域:新生代(Young Generation)和老生代(Old Generation)。

  1. 新生代:

    • 主要存放生命周期较短的对象。
    • 分为两个半区(From SpaceTo Space),使用Scavenge算法进行垃圾回收。当From Space满时,会进行垃圾回收,存活的对象会被复制到To Space,并交换From SpaceTo Space的角色。
  2. 老生代:

    • 主要存放生命周期较长的对象。
    • 使用标记清除算法或标记整理算法(Mark-Compact)进行垃圾回收。当老生代内存占用达到一定阈值时,会触发垃圾回收。

总结

在V8引擎中,垃圾清除的具体过程依赖于对象的存放区域:

  • 新生代:通过Scavenge算法,将存活的对象复制到另一个半区,并清理原半区的垃圾。
  • 老生代:使用标记清除或标记整理算法,标记所有可达对象,并清除或整理未被标记的对象所占用的内存。