JavaScript垃圾回收机制

垃圾回收策略

不同的语言有不同的垃圾回收策略

  • 手动回收:C/C++
    • 何时分配内存、何时销毁内存都时由代码控制的
  • 自动回收:JavaScript、python、Java
    • 产生的垃圾数据由垃圾回收器来释放

调用栈中的数据是如何回收的

有一个记录执行状态的指针(ESP),当某个函数(能够创建执行上下文的代码)执行完毕,ESP就会下移,这个下移操作就是销毁已经执行完函数的上下文过程

所以:调用栈中的数据是通过向下移动ESP来销毁函数保存在栈中的执行上下文

堆中的数据如何回收

虽然调用栈的数据被回收了,但是调用栈中变量引用了堆中的数据是没有被销毁的

这个时候,就需要用到JavaScript中的”垃圾回收器“了

代际假说和分代收集

代际假说
  • 大部分对象在内存中存在的时间很短,简单来说,就是很多对象一经分配内存,很快就变得不可访问
  • 不死的对象,会活得很久,例如:window、document、window下的全局对象

通常,垃圾回收算法有很多种,但是并没有哪一种能胜任所有的场景,需要权衡各种场景,根据对象的生存周期的不同而使用不同的算法,以便达到更好的效果。

所以:V8把堆分为”新生代“和”老生代“两个区域,新生代种存放的是生存时间短的对象老生代存放的是生存时间久的对象

新生区通常只支持1-8M的容量,而老生区支持的容量就大很多了。对于这两块区域,V8分别使用两个不同的垃圾回收器,以便更高效的实施垃圾回收

副/主垃圾回收器

  • 副垃圾回收器,主要负责新生代的垃圾回收
  • 主垃圾回收器,主要负责老生代的垃圾回收

垃圾谁后期的工作流程

无论什么类型的垃圾回收器,它们都有一套共同的执行流程

  1. 标记空间的”活动对象“和”非活动对象
    • 活动对象:还在使用的对象
    • 非活动对象:可以进行垃圾回收的对象
  2. 回收”非活动对象“所占据的内存。其实就是在标记完成之后,统一清理内存种所有被标记为可回收的对象
  3. 内存整理(可选
    • 频繁回收对象后,内存种就存在大量不连续空间,我们把这些不连续的内存空间称为”内存碎片
    • 当内存中出现了大量的内存碎片之后,如果需要分配较大连续内存的时候,就可能出现内存不足的情况。
    • 所以需要整理这些内存碎片

副垃圾会回收器

主要负责:新生区的垃圾回收。而通常情况下,大多数小的对象都会被分配到新生区,所以说,这个区域虽然不大,但是垃圾回收还是比较频繁的。

Scanvenge算法

把新生代空间对半划分为两个区域,一般是对象区域,一般是空闲区域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nw98PLDv-1586883897078)(I:\myFuture\桌面资料\面试\学习图片\新生区划分为对象区域和空闲区域.png)]

新加入的对象都会存放到对象区域,当对象区域快被写满时,就需要执行一次垃圾清理操作。

在垃圾回收过程中,首先要对对象区域中的垃圾做标记;标记完成之后,就进入垃圾清理阶段,副垃圾会后器会把这些存活的对象复制到空闲区域中,同时它还会把这些对象有序地排列起来,所以这个复制过程,相当于完成了内存整理操作,复制后空闲区域就没有内存碎片了。

完成复制后,对象区域与空闲区域继续”角色翻转“,也就是原来地对象区域变成空闲区域,原来地空闲区域变成了对象区域。这样就完成了垃圾对象地会后操作,同时这样”角色翻转地操作还能让新生代中地两块区域无线重复使用下去

缺点:

每次执行清理操作时,都需要将存活地对象从对象区域复制到空闲区域。但复制操作需要时间成本,如果新生代空间设置太大了,那么每次清理地时间就会过很久,所以”为了执行效率,一般新生区地空间会被设置得比较小

也就是因为新生区地空间不大,所以很容易被存活地对象装满整个区域。为了解决这个问题,JavaScript引擎采用了”对象晋升策略“,也就是经过两次垃圾回收依然存活地对象,会被转移到老生去中

主垃圾回收器

负责对象:

  • 新生区晋升地对象:存活时间长
  • 一些大的对象会被直接分配到老生区:占用空间大
标记-清除算法
  • 标记过程阶段:从一组根元素开始,递归遍历这个根元素,在这个遍历过程中,能到达的元素称为”活动元素“,没有到达的元素可以判断为”垃圾数据

  • 垃圾清除过程:清除掉空色标记的数据

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehsfyjqV-1586883897092)(I:\myFuture\桌面资料\面试\学习图片\标记清除过程.png)]

    • 这样会长生大量不连续的内存碎片。而碎片过多会导致大对象无法分配到足够的连续内存,于是又长生了另外一种算法——”标记-整理
标记-整理

主题过程和”标记-清除“算法一样,但是后续步骤不是直接对可回收对象进行整理,而是让所有活动对象都向一端移动,然后清理掉端边界以外的内存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VdV3oQLH-1586883897102)(I:\myFuture\桌面资料\面试\学习图片\标记整理过程.png)]

全停顿

已经知道V8是使用副垃圾回收器和主垃圾回收器处理垃圾回收的,不过由于JavaScript是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的JavaScript脚本停顿下来,待垃圾回收完毕后再回复脚本执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qinx8wOg-1586883897129)(I:\myFuture\桌面资料\面试\学习图片\全停顿.png)]

在V8新生代的垃圾回收中,因其空间较小,且存活对象较少,所以全停顿的影响不大,但老生代就不一样了。

增量标记算法

为了降低老生代的垃圾回收而造成的卡顿,V8将标记过程分为一个个的子标记过程,同时让垃圾回收标记个JavaScript应用逻辑交替进行,直到标记阶段完成,我们把这个算法称为”增量标记算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrXnY68o-1586883897135)(I:\myFuture\桌面资料\面试\学习图片\增量标记.png)]

因为将一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他JavaScript任务中间执行,这样当执行动画效果时,就不会让用户因为垃圾回收任务而感受到页面的卡顿了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值