宝哥软件园

Node.js的GC机制详解

编辑:宝哥软件园 来源:互联网 时间:2021-08-23

V8的内存限制

在一般的后端开发语言中,对基本的内存使用没有限制。但是在Node中通过JavaScript使用内存时,会发现只能使用部分内存(64位系统约1.4GB,32位系统约0.7GB)。在这种限制下,将导致节点无法直接操作大内存对象。

出现这个问题的主要原因在于Node的JavaScript执行引擎V8。

在V8中,所有的JavaScript对象都是通过堆来分配的。Node提供了一种方法来检查V8中的内存使用情况

process.memoryUsage().

HeapTotal已申请堆内存heap当前使用的堆内存为什么V8应该限制堆的大小:

1.V8是为浏览器设计的,不太可能遇到占用大量内存的场景

2.2的限制。V8的垃圾收集机制。(根据官方说法,以1.5GB垃圾收集堆内存为例,V8做一个小垃圾收集需要50ms以上,非增量垃圾收集需要1s以上)

V8提供了允许我们控制内存使用量的选项

用node-max-old-space-size=1700 test . js设置老一代的最大内存空间,用MB node-max-new-space-size=1024 test . js设置新一代的最大内存空间,可惜这两个最大值需要在启动时执行。这意味着V8使用的内存无法根据使用情况自动扩展,当内存分配超过限制值时,会造成进程错误。

V8的垃圾收集机制

V8的垃圾收集策略主要基于世代垃圾收集机制。在V8中,内存主要分为两代:新一代和老一代。新生代的物体是生存时间短的物体,老一代的物体是生存时间长的物体或记忆驻留的物体。

V8堆的整体大小是新一代的内存空间加上老一代的内存空间

清除算法

在生成的基础上,新一代中的对象主要是通过choose算法收集的垃圾。切尼算法主要用于扫气的实现。

切尼算法是一种通过复制实现的垃圾收集算法。它将堆内存分成两部分,每一部分空间都变成了半空间。在这两个半空间中,只有一个在使用,另一个闲置。使用中的半空间变成从空间,空闲空间变成到空间。当我们分配对象时,我们首先在From空间中分配它们。当垃圾收集开始时,将检查“从”空间中幸存的对象,并将这些幸存的对象复制到“到”空间,同时释放非幸存对象占用的空间。复制后,“从空间”和“到空间”的角色互换。

扫取的缺点是只能使用堆内存的一半,但是扫取在时间效率上非常出色,因为它只复制幸存的对象,对于生命周期短的场景,只占幸存对象的一小部分。清除是一种典型的以牺牲空间换取时间的算法,不能大规模应用于所有垃圾收集,但非常适合在新一代中应用。

促进

把物体从新生代移动到老一代的过程叫做提升。

在复制到到到空间之前,需要检查从空间中幸存的对象。在一定条件下,需要将存活期较长的对象迁移到老一辈,即完成对象的提升。

晋升有两个主要条件:

1.这个物体被回收过一次吗

2.到空间已使用超过25%

将限制值设置为25%的原因是,清除完成后,“到”空间将成为“从”空间,下一次内存分配将在该空间中进行。如果比例过高,会影响后续的内存分配。

标记-扫描标记-压缩

在老一代中,V8主要使用Mark-Sweep和Mark-Compact的组合进行垃圾收集。

标记-清除是指标记清除,分为标记和清除两个阶段。标记-扫描在标记阶段遍历堆中的所有对象,并标记活动对象。在随后的清除阶段,仅清除未标记的对象。

Mark-Sweep最大的问题是在标记清除和回收后,内存空间会处于不连续状态。这种内存碎片会给后续的内存分配带来问题,因为很可能需要分配一个大对象。此时所有碎片化的空间都无法完成这种分配,会提前触发垃圾回收,这种回收是不必要的。

为了解决标记扫描的内存碎片问题,提出了标记压缩。标记紧凑是指标记整理,它是在标记扫描的基础上发展而来的。两者的区别在于,物体被标记为死亡后,在排序过程中将活的物体移动到一端,移动完成后,直接清除边界外的记忆。

下表是三种主要垃圾收集算法的简单比较

从表中可以看出,在Mark-Sweep和Mark-Compact之间,由于Mark-Compact需要移动对象,其执行速度不可能很快。所以在取舍方面,V8主要采用Mark-Sweep,只有在没有足够空间分配新一代提升的对象时才采用Mark-Compact。

增量标记

为了避免JavaScript应用逻辑与垃圾收集器视图不一致,三种垃圾收集算法都需要暂停应用逻辑,这被称为“停止世界”。

由于新生代分配空间小,残存物少,总停顿对新生代影响不大。而老一辈通常分配空间大,存活对象多,因此满垃圾收集的标记、清理、排序造成的停顿会很可怕。

为了减少全堆垃圾收集造成的暂停时间,V8从标记阶段开始,将原本应该一口气完成的动作改成了增量标记,即分成很多小“步骤”,每个“步骤”后执行一小段时间的JavaScript应用逻辑,垃圾收集和应用逻辑交替执行,直到标记阶段完成。

V8经过增量标记改进后,垃圾收集的最大暂停时间可以减少到原来的1/6左右。

查看垃圾收集日志

查看垃圾收集日志的主要方式是在启动时添加- trace_gc参数。

摘要

1.1的JavaScript执行引擎。节点是V8,内存的使用和控制也受到V8的限制。

2.V8将内存分为新一代和老一代,分别存储短命和长命或者内存驻留对象。

3.在新一代中,垃圾回收采用了choose算法,它的优点是速度快,没有内存碎片,但缺点是占用双倍的内存空间。

4.在老一代中,标记-扫描和标记-压缩一起使用,主要使用标记-扫描。优点是不需要移动对象,缺点是会产生内存碎片。Mark-Compact是Mark-Sweep的补充,在没有足够的空间分配新提升的对象时,它会整理内存并清理内存碎片,但移动对象的速度很慢。

5.V8使用增量标记来减少完全静止的影响。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

更多资讯
游戏推荐
更多+