V8 的垃圾回收机制

V8的内存限制

在64位系统下, V8最多只能分配1.4G, 在 32 位系统中,最多只能分配0.7G。你想想在前端这样的大内存需求其实并不大,但对于后端而言,nodejs如果遇到 一个2G多的文件,那么将无法全部将其读入内存进行各种操作了
机器的内存明明有几十G,为什么会有这样的内存限制?
究其原因,有以下两方面的原因, 一个是JS单线程的执行机制,另一个是JS垃圾回收机制的限制。

  • 首先JS是单线程运行的,这意味着一旦进入到垃圾回收,那么其它的各种运行逻辑都要暂停;
  • 垃圾回收其实是非常耗时间的操作,以 1.5GB 的垃圾回收堆内存为例,V8 做一次小的垃圾回收需要50ms 以上,做一次非增量式(ps:后面会解释)的垃圾回收甚至要 1s 以上。
    这么长的时间内,我们的JS代码执行会一直没有响应,造成应用卡顿,导致应用性能和响应能力直线下降。 v8 初始的时候是给浏览器使用的 ,对于web 页面操作 已经完全够用了。

*V8 把堆内存分成了两部分进行处理——新生代内存和老生代内存。顾名思义,新生代就是临时分配的内存,存活时间短, 老生代是常驻内存,存活的时间长 *

新生代内存的回收

**新生代采用 Scavenge算法 **
在这里插入图片描述
From部分表示正在使用的内存,To 是目前闲置的内存.
当进行垃圾回收时,V8 将From部分的对象检查一遍,如果是存活对象那么复制到To内存中(在To内存中按照顺序从头放置的),之后直接把Form区域全部清空。
当所有的From中的存活对象按照顺序进入到To内存之后,From 和 To 两者的角色对调,From现在被闲置,To为正在使用,如此循环。

由于堆内存是连续分配的,这样零零散散的空间可能会导致稍微大一点的对象没有办法进行空间分配, 这种零散的空间也叫做内存碎片,在To 内存中从头排列就是为了解决内存碎片的问题

老生代内存回收

那么新生代中的变量如果经过多次回收后依然存在,那么就会被放入到老生代内存中,这种现象就叫晋升。
那些情况需要晋升到老生代:

  • 至少经历过一轮 Scavenge算法;
  • to 空间的内存占用超过 25%;
    老生代的gc , 采用Mark Sweep(标记清除)、Mark Compact(标记整理)。
  1. 首先会遍历堆中的所有对象, 对它们做上标记,然后对于代码环境中使用的变量以及被强引用的变量取消标记,剩下的就是要删除的变量了,在随后的清除阶段对其进行空间的回收。
  2. 整理内存碎片。V8 的解决方式非常简单粗暴,在清除阶段结束后,把存活的对象全部往一端靠拢。

增量标记

由于JS的单线程机制,V8 在进行垃圾回收的时候,不可避免地会阻塞业务逻辑的执行,倘若老生代的垃圾回收任务很重,那么耗时会非常可怕,严重影响应用的性能。
那这个时候为了避免这样问题,V8 采取了增量标记的方案,即将一口气完成的标记任务分为很多小的部分完成,每做完一个小的部分就"歇"一下,就js应用逻辑执行一会儿,
然后再执行下面的部分,如果循环,直到标记阶段完成才进入内存碎片的整理上面来。其实这个过程跟React Fiber的思路有点像,可中断的更新机制

React Fiber More

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值