javascript 垃圾回收机制--分代式垃圾回收机制

以前对 javascript 的垃圾回收机制没有深入了解过。以为只是简单的标记清除法。即从根对象开始找它的引用,然后依次往后找它引用的引用,依次递归,将所有被引用的变量打上标记。然后在遍历完后,清除没有被标记的变量。

具体文章可以参考 mdn:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management

但是 javascript 中 v8 引擎中的垃圾回收机制比这个要稍微复杂一些。

什么是 v8 引擎

javascript 并不能被系统底层所能识别,需要有一个转换器将 js 转换成 CPU 所认识的汇编语言。 javascript v8 引擎就是这样的一种转换器,可以将 javascript 代码转换成不同架构 CPU 的所识别的汇编语言。但 v8 引擎并不仅仅起着编译的作用,还负责代码的执行和内存分配工作。

v8 引擎是 chrome 的。但是因为其出色的性能,因而被 nodejs 采用作为 js 解释器。

分代式垃圾回收机制

v8 中将内存分成两个区,一个是新区(young space)一个是旧区(old space)
新区要比旧区小
新区内存的最大值在 64 位和 32 位系统上分别是 32MB 和 16MB
(因此我们在使用 node 时,如果想要扩展 node 的内存大小可以使用 --max-old-space-size 和 --max-new-space-size 来调整新区和旧区的内存大小)

区分于新区和旧区的依据是:对象的存活时间
新区存放的对象存活时间较短,而旧区中存放的对象时间较长或常驻内存的对象。

在新区中采用 scavenge 策略

即将新区又分成两部分,一部分是闲置的叫做 To 空间,一部分是新区使用的内存叫做 From 空间。新区使用的内存会遍历一遍,检查活着的对象,然后将活着的对象复制到 To 空间中,将 From 空间清空,然后将 From 和 To 区对换。即可完成一次新区的垃圾回收。

在旧区中采用 mark-sweep 标记清除 和 mark-compact 标记整理

旧区中存活的对象较多,复制存活的对象效率会很低。并且如果旧区比较大,如果分成两个区会浪费一半的空间。因此在旧区中使用 mark-sweep 和 mark-compact
遍历堆中的对象,标记活着的对象。遍历完后进行清除未标记的。

这样清除了未标记的对象后,会又很多零碎(不连续)的内存空间,这样的碎片内存空间会对之后的内存分配造成问题。因为很可能出现一个很大的对象,这是所有的碎片空间都满足不了此次分配,就会提前触发垃圾回收,而这次回收是不必要的。

因此会在标记清除后移动存活对象的内存空间使其内存空间连续,这样就不存在零碎的内存空间。

垃圾回收的时机

为了避免垃圾回收机制运行过程中,javascript 运行改变内存。垃圾回收机制运行过程中javascript 停止运行。在垃圾回收完成后, javascript 继续执行应用逻辑。
在一次小垃圾回收只收集新区,由于新区默认配置得较小,且其中存活对象通常较小,所以即使停顿也影响不大。
但是旧区很大,且存活对象较多,停顿时间会很长影响性能。因此旧区进行优化:
增量标记: 将一次垃圾回收分成很多小步,每次做完一小步,就让 javascript 执行一会,垃圾回收和应用逻辑交替执行直到标记阶段完成。

参考:
v8引擎如何工作
js内存管理
chrome v8 garbage collect
《深入浅出node.js》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值