Skip to content

V8 garbage collector

Posted on:November 22, 2023

你我写的 js 都是垃圾

作用

​ 为了性能,防止过多内存被占用而导致性能下降

垃圾回收方式

标记清除

标记-整理算法

老生代中的标记-整理算法是为了解决标记-清除算法可能产生的内存碎片问题。在标记-整理算法中,清除阶段不直接清除垃圾对象,而是让存活的对象向内存的一端移动,然后清理掉移动后端的所有垃圾对象。通过这种方式,内存中的存活对象被紧凑地排列在一起,减少了内存碎片的产生。

引用计数法

然而,引用计数在处理循环引用时可能会导致内存泄漏,因为循环引用的对象的引用计数永远不会变为0。

分代垃圾回收

这是一种更高效的垃圾回收策略,根据对象的存活时间将内存分为不同的代(generation)。通常将内存分为年轻代(young generation)和老年代(old generation)。大部分对象在创建后很快就会变得不可访问,所以年轻代会经常进行垃圾回收,而老年代则相对较少。这种方式可以更快地回收大部分短期不用的对象。

增量垃圾回收

在增量垃圾回收中,垃圾回收器将整个垃圾回收过程分为多个小步骤,交替执行垃圾回收和程序代码。这样可以减少单次垃圾回收的暂停时间,使回收过程更平滑,减少对程序性能的影响。

image9bd7418f050d2c17.md.png

垃圾回收策略

​ V8的垃圾回收策略主要是基于分代式垃圾回收机制,其根据对象的存活时间将内存的垃圾回收进行不同的分代,然后对不同的分代采用不同的垃圾回收算法。

​ 为了更快进行垃圾回收,将堆划分成两个区域:新生代老生代

新生代

​ 新生代中分了两个区域,to 空间和 from 空间,主要工作流程如下。

image687d4a519e857532.md.png

image811f7e9691026816.md.png

image6c28744a577e2ec8.md.png

image80b673e5cca7aeca.md.png

imageeae95d238f3673e3.md.png

当然,如果有些变量一直被引用,那么就需要携带这些变量进行处理。

所以为了解决上述问题,当某个元素经历过一次上述交换,或者 to 空间内存超过 25% 则会将元素放入老生代

老生代

​ 在老生代中管理大量内存,如果继续使用上述算法则会浪费一半内存,所以使用之前提到的标记清除算法,具体过程就如上面所说的一样。

​ 清除完毕,因为储存的位置可能是不连续的,利用率可能会下降,所以就需要用到标记整理算法。

​ 由于js 是单线程的,如果上述流程执行时间过长可能会造成卡顿(全停顿)。所以使用增量垃圾回收

​ 同时为了充分利用多核CPU的性能,也将引入并行标记和并行清理,进一步地减少垃圾回收对主线程的影响,为应用提升更多的性能。

参考: