简述 node/v8 中的垃圾回收机制
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 293
Author 回答者: shfshanyue
v8
中的垃圾回收机制分为三种
Scavenge
,工作在新生代,把from space
中的存活对象移至to space
Mark-Sweep
,标记清除。新生代的某些对象由于过度活跃会被移至老生代,此时对老生代中活对象进行标记,并清理死对象Mark-Compact
,标记整理。
相关链接
Author 回答者: wjw-gavin
当一个函数执行结束之后,JavaScript 引擎会通过向下移动 ESP 来销毁该函数保存在栈中的执行上下文。 要回收堆中的垃圾数据,就需要用到 JavaScript 中的垃圾回收器了。 代际假说(The Generational Hypothesis),是垃圾回收领域中一个重要的术语,后续垃圾回收的策略都是建立在该假说的基础之上的,所以很是重要。 代际假说有以下两个特点:
- 大部分对象在内存中存在的时间很短,简单来说,就是很多对象一经分配内存,很快就变得不可访问;
- 是不死的对象,会活得更久。 在 V8 中会把堆分为新生代和老生代两个区域,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。 ● 副垃圾回收器,主要负责新生代的垃圾回收。 ● 主垃圾回收器,主要负责老生代的垃圾回收。
全停顿
增量标记
使用增量标记算法,可以把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,增强用户体验。
参考: 浏览器工作原理与实践
Author 回答者: Echo-MakeGreatEffort
V8引擎的垃圾回收机制非常复杂,随着版本的更新不断改进。以下是V8引擎中常用的几种垃圾回收机制:
-
Scavenge(清除)回收机制:
- Scavenge是一种针对新生代对象的垃圾回收策略。V8将堆内存分为新生代(young generation)和老生代(old generation)。新生代内存主要用于存储生命周期较短的对象。Scavenge使用的是复制算法(copying algorithm),它将新生代内存进一步分为两个区域:From空间和To空间。垃圾回收时,存活的对象会从From空间复制到To空间,然后清空From空间,这样可以有效地减少内存碎片。
-
Mark-Sweep(标记-清除)回收机制:
- Mark-Sweep主要用于清理老生代对象。当堆内存中对象变得老化,进入老生代后,V8会使用Mark-Sweep算法。该算法分为两个阶段:首先是标记阶段,它遍历堆中的所有对象,并标记出仍然存活的对象;然后是清除阶段,回收那些未被标记的对象的内存。
-
Mark-Compact(标记-压缩)回收机制:
- Mark-Compact是Mark-Sweep的改进版本,解决了Mark-Sweep可能造成的内存碎片问题。这个机制在标记出存活对象后,会将存活的对象压缩到堆的一端,清空压缩后的另一端空间,从而避免碎片化。
-
Incremental Marking(增量标记):
- 增量标记是为了减少垃圾回收对应用程序的暂停时间(Stop-the-World)而引入的。V8会将标记过程拆分为多个小步骤,插入到程序执行中,这样就不会一次性占用大量时间,从而提高应用的响应性。
-
Lazy Sweeping(懒惰清除):
- 在清除阶段,V8不再一次性清除所有的不可达对象,而是将清除操作分散到后续的内存分配过程中,以减少垃圾回收对程序运行的影响。
-
Parallel and Concurrent GC(并行与并发GC):
- V8在垃圾回收的某些阶段(例如标记阶段)引入了并行和并发处理。并行GC指的是在多核CPU上并行地执行垃圾回收任务,而并发GC允许垃圾回收与应用程序的执行同时进行,从而减少停顿时间。
这些机制的结合,使得V8在执行垃圾回收时能够高效地管理内存,减少对应用程序性能的影响。