GC 垃圾回收机制
本文为文章《「硬核JS」你真的了解垃圾回收机制吗?》学习笔记,在阅读前强烈建议阅读此文章。
什么是GC?
GC
即 Garbage Collection
,程序在工作过程中会产生很多垃圾,这些垃圾是程序不再使用的空间。GC的作用就是负责回收这些空间。
垃圾是如何产生的?
- 内存分配:当执行JavaScript代码时,
V8
引擎会在内存中为各种对象(如数组、字符串、对象字面量等)分配空间。 - 垃圾产生:在JavaScript程序中,变量和对象的引用关系会随着程序的执行而不断变化。当某个对象不再被任何变量或对象引用时,它所占用的内存空间就变成了“垃圾”。
如何找出垃圾?
目前,主流的垃圾回收算法包括两种:
-
标记清除算法(Mark-and-Sweep):
- 标记阶段:从根集合(如全局对象)开始,遍历所有可达的对象,并标记它们为“已引用”。
- 清除阶段:遍历堆中的所有对象,将未被标记为“已引用”的对象视为垃圾,并回收它们所占用的内存。
-
引用计数算法(Reference Counting):
- 每个对象维护一个引用计数器,每当有一个新的引用指向它时,计数器加1;每当一个引用离开作用域或被设置为
null
时,计数器减1。 - 当对象的引用计数器为0时,表示没有任何引用指向它,因此可以安全地回收其内存。
注意:虽然引用计数算法实现简单,但它存在循环引用的问题,即两个对象相互引用,但不再被外部引用,导致它们无法被回收。因此,现代JavaScript引擎(如V8)主要采用标记清除算法。
- 每个对象维护一个引用计数器,每当有一个新的引用指向它时,计数器加1;每当一个引用离开作用域或被设置为
如何清除垃圾?
V8引擎将堆内存分为两个主要区域:新生代(Young Generation)和老生代(Old Generation)。
-
新生代:
- 主要存放生命周期较短的对象。
- 分为两个半区(
From Space
和To Space
),使用Scavenge
算法进行垃圾回收。当From Space
满时,会进行垃圾回收,存活的对象会被复制到To Space
,并交换From Space
和To Space
的角色。
-
老生代:
- 主要存放生命周期较长的对象。
- 使用标记清除算法或标记整理算法(Mark-Compact)进行垃圾回收。当老生代内存占用达到一定阈值时,会触发垃圾回收。
总结
在V8引擎中,垃圾清除的具体过程依赖于对象的存放区域:
- 新生代:通过
Scavenge
算法,将存活的对象复制到另一个半区,并清理原半区的垃圾。 - 老生代:使用标记清除或标记整理算法,标记所有可达对象,并清除或整理未被标记的对象所占用的内存。