V8垃圾回收机制

V8内存限制
存在限制:Chrome限制了v8内存的使用,(64位约1.4G/1464MB , 32位约0.7G/732MB),这将导致无法直接操作大内存对象。
限制原因:①表层原因为V8最初为浏览器而设计,不太可能遇到用大量内存的场景,②深层原因是V8的垃圾回收机制的限制,(如果清理大量的内存垃圾是很耗时间,这样回引起JavaScript线程暂停执行的时间,那么性能和应用直线下降)
限制选项:V8的内存也是可以修改的,主要考虑使用场景,修改的方法

node --max-old-space-size=1700 test.js //单位为MB
node --max-new-space-size=1024 test.js //单位为MB

上述参数在V8初始化时生效,一旦生效就不能在动态改变。

V8垃圾回收机制算法
内存垃圾回收算法有很多种类(标记清楚算法,引用计数法,复制算法,标记压缩算法,分代垃圾回收法,RC Immix算法 等等)算法很多中,但没有哪一种能够胜任所有场景的使用。
V8的垃圾回收策略主要是分代式垃圾回收机制。

V8内存分代
v8 分代示意图:
    

V8 整体内存大小 =  新生代+ 老生代,默认情况下,新生代的内存大小为(64位16MB,32位8MB),新生代内存大小在V8启动时就指定了,不能根据使用情况来自动扩充。


Scavenge算法
在V8中,新生代的 对象垃圾回收主要通过Scavenge算法进行垃圾回收。在Scavenge的具体实现中,主要采用了Cheney算法:

通过复制的方式实现的垃圾回收算法。(简单理解--只复制活着的对象)它将堆内存分为两个 semispace,一个处于使用中(From空间),另一个处于闲置状态(To空间)。当分配对象时,先是在From空间中进行分配。当开始进行垃圾回收时,会检查From空间中的存活对象,这些存活对象将被复制到To空间中,而非存活对象占用的空间将会被释放。完成复制后,From空间和To空间的角色发生对换。在垃圾回收的过程中,就是通过将存活对象在两个 semispace 空间之间进行复制。



年轻分代中的对象有机会晋升为年老分代,条件主要有两个:

①对象是否经历过Scavenge回收:


②To空间的内存占用比超过限制:


设置25%这个限制值的原因是当这次Scavenge回收完成后,这个To空间将变成From空间,接下来的内存分配将在这个空间中进行。如果占比过高,会影响后续的内存分配。


Mark-Sweep & Mark-Compact  算法

  对于年老分代中的对象,由于存活对象占较大比重,再采用上面的方式会有两个问题:一个是存活对象较多,复制存活对象的效率将会很低;另一个问题依然是浪费一半空间的问题。为此,V8在年老分代中主要采用了Mark-Sweep(标记清除)标记清除和Mark-Compact(标记整理)相结合的方式进行垃圾回收。


①Mark-Sweep(标记清除)

mark-sweep 分为两个阶段,标记和清除阶段。在标记阶段中遍历堆中所有对象,并标记活着的对象,在随后的清除阶段中,只清除没有标记的对象。(简单理解--只清理死亡对象

mark-sweep内存碎片问题是有清理死亡对象后,内存空间出现不连续的状态,这种内存碎片会对后续的内存分配造成问题,因为很可能出现需要分配一个大对象的情况,这是所有的碎片空间都无法完成此次分配。为了解决这个碎片问题提出了mark-compact

②Mark-Compact(标记整理)

mark-compact对于标记死亡对象的整理过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。(简单理解--整理活着对象向一段移动,另一端直接清空


上诉三种垃圾回收算法的简单对比

  

回收算法Mark-SweepMark-CompactScavenge
速度中等最慢最快
空间开销少(有碎片)少(无碎片)双倍空间(无碎片)
是否移动对象
从上表可以看出,在Mark-Sweep和Mark-Compact之间,由于Mark-Compact需要移动对象,所以它的执行速度不可能很快,所以在取舍上,V8主要使用Mark-Sweep,在空间不足以对从新生代中晋升过来的对象进行分配时才使用Mark-Compact。


Incremental Marking (增量标记)

由于对象复制/标记清除/标记整理的回收期间内,V8会暂停所有正在执行业务的代码,待执行完成垃圾回收后再恢复执行业务代码,这被称为--“全停顿”。这种“全停顿”,如果随着堆大小的增长,停顿的时间会急速增加,那么会造成停顿的现象非常厉害。因此V8在标记期间,采用了增量标记的方法,将标记的过程拆分成很多小“步进”,每做完一“步进”就让务代码的执行一小会,再标记,形成循环交替执行标记直到标记阶段完成。这样把原来应用程序停顿的整个时间就会变分拆成多个细小的时间片,极大的提高了应用程序的响应度。



Lazy sweeping(惰性清除)
当增量标记完成后,惰性清除开始此时所有对象都已被标记成或生或死,堆已经准确知道可以回收多少内存,然而此时不必去一次全部回收死去的对象,可以采用延迟清理的处理手段,垃圾回收器可以根据需要来选择回收部分内存, 直到全部垃圾对象回收完毕,整个增量标记-惰性清除的 周期结束。

其它优化
V8已经加入了并行清除,主线程不会操作已死对象,由独立的线程来负责回收死对象的内存,整个过程只需要非常少量的同步操作。同时V8正在实验并行标记,并将在今后引入这一技术。
总结
根据内存垃圾回收使用的场景,去选择不同的垃圾回收算法。
 

《垃圾回收的算法与实现》《垃圾回收算法手册 自动内存管理的艺术》等书籍




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值