高级前端js【Q291】简述 node/v8 中的垃圾回收机制

简述 node/v8 中的垃圾回收机制

Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 293

Author 回答者: shfshanyue

v8 中的垃圾回收机制分为三种

  1. Scavenge,工作在新生代,把 from space 中的存活对象移至 to space
  2. Mark-Sweep,标记清除。新生代的某些对象由于过度活跃会被移至老生代,此时对老生代中活对象进行标记,并清理死对象
  3. Mark-Compact,标记整理。

相关链接

  1. 主流的垃圾回收机制都有哪些?
  2. 各种编程语言的实现都采用了哪些垃圾回收算法

Author 回答者: wjw-gavin

当一个函数执行结束之后,JavaScript 引擎会通过向下移动 ESP 来销毁该函数保存在栈中的执行上下文。 要回收堆中的垃圾数据,就需要用到 JavaScript 中的垃圾回收器了。 代际假说(The Generational Hypothesis),是垃圾回收领域中一个重要的术语,后续垃圾回收的策略都是建立在该假说的基础之上的,所以很是重要。 代际假说有以下两个特点:

  1. 大部分对象在内存中存在的时间很短,简单来说,就是很多对象一经分配内存,很快就变得不可访问;
  2. 是不死的对象,会活得更久。 在 V8 中会把堆分为新生代和老生代两个区域,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。 ● 副垃圾回收器,主要负责新生代的垃圾回收。 ● 主垃圾回收器,主要负责老生代的垃圾回收。

全停顿 1620974853612-a480b43e-b3bb-452f-a502-3a0162548a7f

增量标记 1620975019709-efc33748-fbfc-4fb5-a19d-97abadbf8f97

使用增量标记算法,可以把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,增强用户体验。

参考: 浏览器工作原理与实践

Author 回答者: Echo-MakeGreatEffort

V8引擎的垃圾回收机制非常复杂,随着版本的更新不断改进。以下是V8引擎中常用的几种垃圾回收机制:

  1. Scavenge(清除)回收机制

    • Scavenge是一种针对新生代对象的垃圾回收策略。V8将堆内存分为新生代(young generation)和老生代(old generation)。新生代内存主要用于存储生命周期较短的对象。Scavenge使用的是复制算法(copying algorithm),它将新生代内存进一步分为两个区域:From空间和To空间。垃圾回收时,存活的对象会从From空间复制到To空间,然后清空From空间,这样可以有效地减少内存碎片。
  2. Mark-Sweep(标记-清除)回收机制

    • Mark-Sweep主要用于清理老生代对象。当堆内存中对象变得老化,进入老生代后,V8会使用Mark-Sweep算法。该算法分为两个阶段:首先是标记阶段,它遍历堆中的所有对象,并标记出仍然存活的对象;然后是清除阶段,回收那些未被标记的对象的内存。
  3. Mark-Compact(标记-压缩)回收机制

    • Mark-Compact是Mark-Sweep的改进版本,解决了Mark-Sweep可能造成的内存碎片问题。这个机制在标记出存活对象后,会将存活的对象压缩到堆的一端,清空压缩后的另一端空间,从而避免碎片化。
  4. Incremental Marking(增量标记)

    • 增量标记是为了减少垃圾回收对应用程序的暂停时间(Stop-the-World)而引入的。V8会将标记过程拆分为多个小步骤,插入到程序执行中,这样就不会一次性占用大量时间,从而提高应用的响应性。
  5. Lazy Sweeping(懒惰清除)

    • 在清除阶段,V8不再一次性清除所有的不可达对象,而是将清除操作分散到后续的内存分配过程中,以减少垃圾回收对程序运行的影响。
  6. Parallel and Concurrent GC(并行与并发GC)

    • V8在垃圾回收的某些阶段(例如标记阶段)引入了并行和并发处理。并行GC指的是在多核CPU上并行地执行垃圾回收任务,而并发GC允许垃圾回收与应用程序的执行同时进行,从而减少停顿时间。

这些机制的结合,使得V8在执行垃圾回收时能够高效地管理内存,减少对应用程序性能的影响。