标记清除(Mark-and-Sweep)算法
-
标记阶段(Marking Phase):
-
垃圾回收器首先遍历所有的根对象,这些根对象一般是全局对象、局部变量和函数调用链。
-
对所有能直接或间接从根对象访问到的对象进行标记,表示这些对象还在使用中。
-
-
清除阶段(Sweeping Phase):
-
在标记阶段结束后,垃圾回收器遍历内存中所有的对象,对于没有被标记的对象,认为它们是不再使用的对象。
-
清除这些未被标记的对象,释放其占用的内存空间。
-
垃圾回收机制中的关键概念
-
根对象(Root Objects):
-
根对象是程序执行中直接访问到的对象,如全局变量、局部变量、当前调用栈中的变量等。
-
-
可达性(Reachability):
-
如果一个对象可以通过引用链从根对象到达,则认为该对象是可达的。
-
垃圾回收器通过遍历这些引用链来判断对象是否可达。
-
-
弱引用(Weak References):
-
弱引用不会阻止对象被垃圾回收。WeakMap 和 WeakSet 提供了对对象的弱引用。
-
引用计数(Reference Counting)
虽然现代 JavaScript 引擎主要使用标记清除算法,但早期的一些垃圾回收器使用的是引用计数算法。这种算法简单但有一个主要缺点,即循环引用问题。
-
引用计数
-
每个对象维护一个引用计数,当一个新的引用指向该对象时,计数加1,当引用被删除时,计数减1。
-
当引用计数变为0时,对象被认为是不可达的,可以被回收。
-
优化策略
现代 JavaScript 引擎不仅使用基本的标记清除算法,还引入了许多优化策略,如:
-
分代回收(Generational Collection):
-
把对象分为新生代和老生代。新生代对象生命周期较短,老生代对象生命周期较长。不同代的对象采用不同的回收策略,提高回收效率。
-
-
增量标记(Incremental Marking):
-
将标记过程分为多个小步骤,避免一次性暂停应用执行进行标记,减少回收过程对应用性能的影响。
-
-
并发回收(Concurrent Collection):
-
在应用执行的同时进行垃圾回收,进一步减少回收过程对应用的暂停时间。
-