Code前端首页关于Code前端联系我们

敲黑板:JavaScript引擎v8的垃圾回收算法

terry 2年前 (2023-09-27) 阅读数 74 #数据结构与算法

JavaScript垃圾回收机制仍然停留在表面,“它会释放未引用的变量内存”。最近看了《深入浅出》这本书,了解了更多关于v8垃圾回收算法的知识。记录了一些学习笔记。

敲白板:v8引擎垃圾回收算法

敲黑板:javascript v8引擎的垃圾回收算法

V8垃圾回收策略主要基于分代垃圾回收机制。在现代垃圾收集算法中,内存垃圾收集根据对象的生命周期分不同代进行。 ,然后对不同代的内存应用更高效的算法。在V8中,内存主要分为两代:新一代和老生一代。新生代中的对象是生命周期短的对象,而耀代和明代中的对象是生命周期长或常驻内存的对象。

Scavenge算法

基于生成,新生代中的对象主要通过Scavenge算法进行垃圾回收。在Scavenge的具体实现中,主要使用了Cheney算法敲黑板:javascript v8引擎的垃圾回收算法

Cheney算法是一种通过复制实现的垃圾收集算法。它将堆内存分为两部分,每一部分的空间称为semispace。semispace的两个议事厅中,只有一个在使用,另一个处于闲置状态。semispace的活动空间称为From空间,不活动空间称为To空间。当我们分配一个对象时,我们首先将它分配到From空间中。当垃圾收集开始时,将检查 Saka 空间中仍然存活的对象。这个活体对象将被复制到To空间,非活体对象占用的空间将被释放。复制完成后,“源板”和“目标板”角色将恢复。简而言之,在垃圾收集过程中,活的对象在semispace的两个空间之间复制。

Mark-Sweep & Mark-Compact

Scavenge算法是一种牺牲空间换取时间的算法。非常适合生命周期短的新一代。然而,当一个对象被复制了很多次并且生命周期很长时,有可能空间不够,该对象就会被分配给老生一代,必须使用新的算法来收集垃圾。 敲黑板:javascript v8引擎的垃圾回收算法

Mark-Sweep不会将内存空间分成两部分,因此不存在浪费一半空间的行为。与Scavenge复制活动对象不同,Mark-Sweep在标记阶段会遍历堆栈中的所有对象并标记活动对象。在后续的清理阶段,仅清理未标记的对象。可见Scavenge只复制活的东西,而Mark-Sweep只清理死的东西。

标记扫描 执行标记扫描后,内存板将停止。这种类型的内存碎片会给后续的内存分配带来问题,因为很有可能必须分配大对象。此时所有的碎片空间都无法完成分配,会提前触发垃圾回收,这个循环就没有必要了。 Mark-Compact对象被标记为死后,在清理过程中,活的对象被移动到一端。移动完成后,超出边界的内存立即被清理

附加标志

以避免JavaScript应用逻辑。逻辑必须暂停,然后在垃圾收集完成后恢复执行应用程序逻辑。这种行为被称为“完全暂停”,而长期的“完全暂停”浪费收集时间会让用户感觉到明显的滞后,从而对体验产生影响。以1.5GB垃圾堆内存为例,V8执行小垃圾收集需要50毫秒以上,甚至执行非增量垃圾收集需要1秒以上。这是垃圾收集导致 JavaScript 线程暂停执行的时间。随着时间的推移,应用程序的性能和响应能力将会下降。

为了减少全堆垃圾收集带来的停顿时间,V8从标记阶段开始,将最初一次停顿完成的动作改为附加标记(additionalmarking),即分成很多个。小“步”“前进”,每个“步”完成后,会短暂执行 JavaScript 应用逻辑,交替执行垃圾收集和应用逻辑,直至该阶段完成。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门