V8引擎的内存分配

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36520153/article/details/80473525
  1. 在Node中通过JavaScript使用内存时只能使用部分内容,64位系统下约为1.4GB,32位系统下约为0.7GB.
  2. 当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中.如果已申请的堆空间内存不够分配新的对象,将继续申请堆空间,直到堆的大小超过V8的限制为止.
  3. Node在启动时,可以通过设置参数来调整内存限制的大小.
node --max-old-space-size=1700 test.js //设置老生代内存空间最大值,单位为MB
node --max-new-space-size=1024 test.js //设置新生代内存空间最大值,单位为KB

## v8的垃圾回收机制 ##

  • V8的垃圾回收机制
    V8中,主要将内存分为新生代和老生代两代.新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象

  • Scavenge算法(新生代)
    新生代对象主要通过Scavenge算法进行垃圾回收.在Scavenge的具体实现中,主要采用了Cheney算法.
    Cheney算法是一种采用复制的方式实现的垃圾回收算法.它将堆内存一分为二,每一部分空间称为semispace.在这两个semispace空间中,只有一个处于使用中另一个处于闲置状态,
    处于使用状态的空间称为From空间,处于闲置状态的称为To空间.
    当我们分配对象时,先是在From空间中进行分配,当开始进行垃圾回收时,会检查From空间中的存活对象,这些存活对象将被复制到To空间中,而非存活对象将被释放.完成复制后,From空间和To空间的角色发生交换.
    Scavenge算法的缺点:只能使用堆内存的一半.但由于新生代中对象的生命周期较短,所以很适合这个算法.
    当一个对象经过多次复制依然存活时(检查内存地址),它将被认为是生命周期较长的对象,所以随后会被移动到老生代中.从新生代中移到老生代中的过程成为晋升
    对象晋升的条件有两个:
    1.对象是否经历过Scavenge回收
    2.To空间的内存占比超过限制:当要从From空间复制一个对象到To空间时,如果To空间已经使用超过了25%,则这个对象直接晋升到老生代空间中.

  • Mark-Sweep & Mark-Compact(老生代)
    Mark-Sweep是标记清除的意思,它分为标记和清除两个阶段.
    Mark-Sweep在标记阶段遍历堆中所有对象,并标记活着的对象,在随后的清除阶段中,只清除没有标记的对象.
    Scavenge中只复制活着的对象,而Mark-Sweep只清除死亡对象.
    Mark-Sweep的问题: 在进行一次标记清除回收站后,内存空间会出现不连续的状态.当分配一个大对象时,所有的碎片空间都无法完成此次分配,就会提前出发垃圾回收,而这次垃圾回收是不必要的.
    Mark-Compact:当对象被标记为死亡对象后,在整理的过程中,将活着的对象往一端移动,移动完成后,直接清理掉外界外的内存.
  • Incremental Marking
    为了避免出现JavaScript应用逻辑与垃圾回收器看到的不一致情况,垃圾回收的3种基本算法都需要将应用逻辑停下来,待执行完成垃圾回收后再恢复执行应用逻辑,这种行为被成为”停顿”.
    为了降低全堆垃圾回收带来的停顿时间,V8先从标记阶段入手,将原本要一口气停顿完成的动作改为增量标记,也就是拆分为多个小”步”,没完成一”步”就让JavaScript应用逻辑执行一小会,垃圾回收与应用逻辑交替进行直到标记阶段完成.

总结:由于Mark-Compact需要移动对象,所以它执行速度不可能很快,所以在取舍上,V8主要使用Mark-Sweep,在空间不足以从新生代晋升过来的对象进行分配时才使用Mark-Compact.

猜你喜欢

转载自blog.csdn.net/qq_36520153/article/details/80473525