V8 的垃圾收集过程是如何工作的呢

简介: 【8月更文挑战第31天】V8 的垃圾收集过程是如何工作的呢

V8 的垃圾收集过程是其内存管理系统的核心部分,它负责回收那些不再被应用程序使用的内存空间,以避免内存泄漏并提高性能。V8 的垃圾收集过程主要基于分代垃圾收集策略,将内存中的对象分为新生代和老生代,并分别采用不同的算法进行垃圾收集。以下是 V8 垃圾收集过程的具体工作方式:

1. 新生代垃圾收集

新生代是存放新创建对象的内存区域,这些对象往往很快就会被销毁或变得不可达。V8 使用 Scavenge 算法来管理新生代的内存。

Scavenge 算法的工作流程

  • 内存划分:新生代被划分为两个等大的空间,称为 From 空间和 To 空间。新创建的对象会被分配到 From 空间中。
  • 垃圾收集触发:当 From 空间被填满时,会触发一次垃圾收集。
  • 标记存活对象:垃圾收集器会遍历 From 空间中的所有对象,标记出那些仍然被引用的对象(即存活对象)。
  • 复制存活对象:将 From 空间中的存活对象复制到 To 空间中,并维持它们在内存中的相对位置关系。
  • 空间角色翻转:完成复制后,From 空间和 To 空间的角色会互换,原来的 To 空间变为新的 From 空间,用于后续新对象的分配;原来的 From 空间(现在已清空)变为新的 To 空间,等待下一次垃圾收集时的对象复制。

对象晋升:如果一个对象在新生代中经过多次垃圾收集后仍然存活,它会被认为是一个长期存活的对象,并会被晋升到老生代中,以便使用更适合长期存活对象的垃圾收集算法。

2. 老生代垃圾收集

老生代是存放存活时间较长的对象的内存区域。V8 使用标记-清除(Mark-Sweep)和标记-整理(Mark-Compact)算法来管理老生代的内存。

标记-清除算法的工作流程

  • 标记阶段:从一组根对象(如全局对象、当前执行栈中的局部变量等)开始,递归遍历这些对象及其引用的其他对象,标记出所有可达的对象(即存活对象)。
  • 清除阶段:遍历堆中的所有对象,回收那些未被标记为存活的对象所占用的内存空间。

标记-整理算法的工作流程(可选)

  • 在多次执行标记-清除算法后,老生代中可能会产生大量内存碎片,影响后续的内存分配。此时,V8 可以选择执行标记-整理算法来优化内存布局。
  • 标记阶段与标记-清除算法相同,但整理阶段会将所有存活对象移动到内存的一端,形成一个连续的内存块,然后清理掉边界以外的内存空间。

3. 增量标记和并行回收

为了减少垃圾收集对应用程序性能的影响,V8 引入了增量标记和并行回收技术。

  • 增量标记:将垃圾收集的标记过程分解为多个小步骤,每次只执行一小部分标记工作,然后让应用程序继续执行一段时间。这样可以在不完全停止应用程序的情况下逐步完成垃圾收集的标记阶段。
  • 并行回收:在垃圾收集过程中,不仅主线程参与工作,还会利用多个辅助线程来加速标记和清理过程。这可以显著减少垃圾收集所需的总时间。

4. 垃圾收集的影响

需要注意的是,虽然 V8 的垃圾收集器是高度优化的,但在执行垃圾收集时仍然需要暂停应用程序的执行(即所谓的“全停顿”或“Stop-The-World”)。这种停顿虽然通常很短,但在某些情况下仍然可能对应用程序的性能产生影响。因此,开发者在编写 JavaScript 代码时应该尽量避免创建大量短命对象或产生复杂的引用关系,以减少垃圾收集的负担和停顿时间。

目录
相关文章
|
算法 Java 程序员
【GC的过程】
【GC的过程】
|
Java
G1垃圾回收器的工作流程
G1垃圾回收器的工作流程
1863 0
|
4月前
|
算法 Java 开发者
G1垃圾回收器的停顿时间预测模型是如何工作的?
G1垃圾回收器的停顿时间预测模型是如何工作的?
|
5月前
|
Java 运维
开发与运维内存问题之长期存活的对象最终会进入哪个内存区域如何解决
开发与运维内存问题之长期存活的对象最终会进入哪个内存区域如何解决
35 0
|
5月前
|
Java 运维
开发与运维收集问题之G1收集器避免全区域垃圾收集如何解决
开发与运维收集问题之G1收集器避免全区域垃圾收集如何解决
32 0
|
7月前
|
存储 JavaScript 前端开发
V8的GC过程
V8的GC过程
|
存储 算法 Java
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
G1垃圾回收流程 及 垃圾回收器 总结 简述
213 0
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
|
7月前
|
监控 安全
线程死循环是多线程应用程序开发过程中一个难以忽视的问题,它源于线程在执行过程中因逻辑错误或不可预见的竞争状态而陷入永久运行的状态,严重影响系统的稳定性和资源利用率。那么,如何精准定位并妥善处理线程死循环现象,并在编码阶段就规避潜在风险呢?谈谈你的看法~
避免线程死循环的关键策略包括使用同步机制(如锁和信号量)、减少共享可变状态、设置超时、利用监控工具、定期代码审查和测试、异常处理及设计简洁线程逻辑。通过这些方法,可降低竞态条件、死锁风险,提升程序稳定性和可靠性。
105 0
|
7月前
|
算法 Java UED
【JVM】分代收集算法:提升Java垃圾回收效率
【JVM】分代收集算法:提升Java垃圾回收效率
118 0

相关实验场景

更多