垃圾回收

237 阅读5分钟

垃圾回收:js是使用垃圾回收的语言,通过自动内存管理实现内存分配和闲置资源回收。

基本思路: 确定哪个变量不再使用,然后释放它占用的内存。这个过程是周期性的,每隔一段时间就自动运行,开发者不用关心内存分配和回收。

  1. 离开作用域后的值会被自动标记为可回收,然后在垃圾回收期间被删除
  2. 主流的垃圾回收算法是标记清理,即先给当前不使用的值加上标记,再回来回收它的内存
  3. 引用计数是另一种方式,需要记录值被引用的多少次。

什么是垃圾数据

我们在写js代码时,会频繁操作数据。在一些数据不被需要的时候,它就是垃圾数据。这些垃圾数据占用的内存应该被回收。

const dog = new Object()
dog.a = new Array()

当js执行代码时,会首先在全局作用域中添加一个dog属性,并在堆中创建一个空对象,将该对象的地址指向dog。随后又创建了一个大小为1的数组,并将属性地址指向了dog.a

如果我们将dog.a = new Object()

a指向改变了,此时堆中的数组对象就成了垃圾数据,专业名词 【不可达】数据,需要被回收。

垃圾回收算法

可以将过程想象成一个从根溢出的巨大的油漆桶,它从一个根节点出发,将可到达的对象标记染色,移除未标记的。

  1. 标记空间中【可达值】的值

    V8采用的是可达性算法来判断堆中对象应不应该回收。思路:

    1. 从根节点出发, 遍历所有的对象
    2. 可以遍历到的对象,是可达的
    3. 没有被遍历的,是不可达的
  2. 回收【不可达】的值所占的内存

    标记完后,统一清理内存中所有不可达的对象

  3. 内存整理

    1. 频繁回收对象后,内存中就会出现大量不连续空间,专业名词【内存碎片】
    2. 当内存中出现大量内存碎片,如果需要分配较大连续内存时,就有可能出现内存不足的情况。
    3. 最后一步是整理内存碎片

什么时候垃圾回收

浏览器进行垃圾回收时,会暂停了js脚本,等回收完成再继续进行对于普通应用没什么问题,但对于js游戏,动画对连贯性要求较高的应用时,造成页面卡顿。那什么时候回收垃圾,可以避免长时间暂停。

  • 分代收集
  • 增量收集
  • 闲时收集

分代收集

浏览器将数据分为两种:

  • 临时对象

    • 大部分对象在内存中存活时间短。
    • 函数内部声明的变量,函数执行完,变量被销毁。
    • 变量不可访问,应快回收。
  • 长久对象

    • 生命周期长的对象,全局window,DOM,WEBAPI等。
    • 这类对象可以慢点回收。

针对这两种对象,V8将堆分为:

  1. 新生代区域(存放临时对象)==》 副垃圾回收器回收
  2. 老生代区域(存放持久对象)==》 主垃圾回收器回收

主垃圾回收器

负责老生代区域中的长久对象, 特点:

  • 占用空间大
  • 对象存活时间长

它使用【标记 - 清除】的算法执行垃圾回收

  1. 从一组根元素开始,递归遍历这组根元素,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。
  2. 垃圾清除
直接将垃圾数据清除
直接将垃圾数据清除
  1. 内存整理(多次清除后,会产生大量的不连续的内存碎片,需内存整理)
标记整理
标记整理

副垃圾回收器

负责新生代区域中的临时对象的回收,通常只有1-8M的容量。新生代被分为两个区域:

  • 新生区
  • 空闲区

新加入的对象都被放进对象区域,等对象区域满后,会执行一次垃圾清理。

步骤:

  1. 先给对象区域所有垃圾做标记
  2. 标记完后,将存活的对象复制到空闲区域中,并有序排列

副垃圾回收器是没有碎片整理的,因为空闲区本来就是整齐的。

  1. 空闲区与对象区对调

总结: 副垃圾回收操作比较频繁,为了执行效率,一般新生取空间设置的较小,一旦满了就进行垃圾回收。

分代收集:将堆分为新生代老生代,多回收新生代,少回收老生代。这样就减少了每次需要遍历的对象,从而减少垃圾回收耗时。

增量收集

如果脚本中含有许多对象,引擎一次性遍历整个对象,会造成长时间暂停。所以引擎将垃圾收集工作分成更小的块,每次处理一部分,多次处理。 这样就解决了长时间停顿的问题。

闲时收集

垃圾回收器只会在CPU空闲时尝试运行,以减少可能对代码执行的影响。

面试题

1. 浏览器怎么垃圾回收?

三点回答: 什么是垃圾, 如何捡垃圾, 什么时候捡垃圾

什么是垃圾: 不再需要的数据即为垃圾,全局变量随时可以用到,不是垃圾

如何捡垃圾:(遍历算法)

  • 标记空间中可达值
  • 回收不可达值占据的内存
  • 做内存整理

什么时候捡垃圾

  • 前端其特殊性,垃圾回收可能会造成页面卡顿
  • 分代收集、增量收集、闲时收集