【8.14】nodejs 原理学习 - 内存控制(2) - V8 的垃圾回收机制

406 阅读3分钟

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

这是内存控制章节的第二篇文章,V8 的垃圾回收机制

这篇文章是对 深入浅出 nodejs 这本书的第五章 - 内存控制的学习笔记和练习,这是这个系列的第二篇文章,欢迎大家点赞和评论~

上一篇中讲到,由于 V8 垃圾回收机制的限制,nodejs 在使用内存时有一些限制,只能使用部分内存(64位系统下约为1.4 GB,32位系统下约为0.7 GB)

这一篇文章我们通过浅析 V8 的垃圾回收机制,简单的介绍一下原因。

V8 内存垃圾回收的分代方式

V8 的垃圾回收策略主要是分代式垃圾回收机制,按照对象的存活时间,将内存的垃圾回收进行了不同的分代,对不同的分代使用更高效的算法。

在 V8 中,内存主要分为老生代和新生代两代,新生代中式存活时间较短的对象,老生代中为存活时间较长的、或常驻的对象。

image.png

上一篇文章提到的,可以调整内存空间的两种方法中,--max-old-space-size 是设置老生代内存空间大小的,--max-new-space-size 设置新生代内存空间大小。

V8 主要的垃圾回收算法

新生代中的对象

新生代中的对象主要使用 Scavenge 算法进行垃圾回收,Scavenge 主要采用的是 Cheney 算法,Cheney 算法将内存空间一分为二,每一部分空间称为 semispace,两个空间分别叫做 From 和 To,它们一个处于使用中的状态,一个是闲置状态

image.png

对象首先会在新生代 From 空间,根据一定条件判断是否进入 To 空间:

  • 如果对象不再存活,它占用的内存空间将被释放,否则进入后面的判断
  • 如果 To 空间的使用占比超过 25%,对象直接晋升到老生代空间,不进入 To 空间,否则进入后面的判断(因为当次垃圾回收完成后,To 空间会变成 From 空间,如果占比过高,会影响后面的内存分配)
  • 如果对象已经经历过一次 Scavenge 垃圾回收,则会直接晋升到老生代空间,否则会被复制到 To 空间

Scavenge 以内存空间换时间,非常适合存活周期较短的新生代对象

老生代中的对象

老生代中存活的对象占据较大比重,在老生代中再次使用 Scavenge 算法会有两个问题,一是存活对象较多,复制存活对象的效率比较低;另一个问题是会浪费一半空间。老生代中使用的是 Mark-Sweep & Mark-Compact 算法。

Mark-Sweep 是标记清除的意思,标记阶段会遍历内存中的所有对象,标记活着的对象,随后清除过程中,只清除没有标记的对象。

image.png 但是在进行一次标记清除回收后,内存会出现不连续的状态,会对之后的内存分配造成问题。于是提出了 Mark-Compact 算法,在整理对象时,将活着的对象像一端移动,移动完成后,清理掉边界外的内存。

image.png

Mark-Sweep 和 Mark-Compact 在实际使用过程中是结合使用的

垃圾回收算法对比

image.png

考虑到执行速度的原因,V8 主要使用 Mark-Sweep,在空间不足时才会使用 Mark-Compact。

以上是 V8 的垃圾回收机制浅析,欢迎点赞和评论