13|JavaScript 的数据是如何回收的

因为数据是存储在栈和堆两种内存空间中的,所以接下来我们就来分别介绍“栈中的垃圾数据”和“堆中的垃圾数据”是如何回收的。

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

当一个函数执行结束之后,JavaScript 引擎会通过向下移动 ESP 来销毁该函数保存在栈中的执行上下文。

举例:

function foo(){
    var a = 1
    var b = {name:"极客邦"}
    function showName(){
      var c = 2
      var d = {name:"极客时间"}
    }
    showName()
}
foo()

执行到 showName 函数时,那么 JavaScript 引擎会创建 showName 函数的执行上下文,并将 showName 函数的执行上下文压入到调用栈中,与此同时,还有一个记录当前执行状态的指针(称为 ESP),指向调用栈中 showName 函数的执行上下文,表示当前正在执行 showName 函数。

接着,当 showName 函数执行结束之后,ESP 向下移动到 foo 函数的执行上下文中,上面 showName 的执行上下文虽然保存在栈内存中,但是已经是无效内存了。比如当 foo 函数再次调用另外一个函数时,这块内容会被直接覆盖掉,用来存放另外一个函数的执行上下文。

堆中的数据是如何回收的

当上面那段代码的 foo 函数执行结束之后,ESP 应该是指向全局执行上下文的,那这样的话,showName 函数和 foo 函数的执行上下文就处于无效状态了,不过保存在堆中的两个对象依然占用着空间,如下图所示,要回收堆中的垃圾数据,就需要用到 JavaScript 中的垃圾回收器了。

根据对象的生存周期的不同而使用不同的算法,以便达到最好的效果。

区域 对象特征 回收器 算法
新生代区域 生存时间短、占用空间小的对象 副垃圾回收器 Scavenge 算法
老生代区域 生存时间久、占用空间大的对象 主垃圾回收器

标记 - 清除(Mark-Sweep)的算法

标记 - 整理(Mark-Compact)

垃圾回收器的工作流程

  1. 标记空间中活动对象和非活动对象:所谓活动对象就是还在使用的对象,非活动对象就是可以进行垃圾回收的对象。
  2. 回收非活动对象所占据的内存:其实就是在所有的标记完成之后,统一清理内存中所有被标记为可回收的对象。
  3. 做内存整理:当内存中出现了大量的内存碎片之后,如果需要分配较大连续内存的时候,就有可能出现内存不足的情况。所以最后一步需要整理这些内存碎片,但这步其实是可选的,因为有的垃圾回收器不会产生内存碎片,比如接下来我们要介绍的副垃圾回收器。

副垃圾回收器

新生代中用 Scavenge 算法来处理。所谓 Scavenge 算法,是把新生代空间对半划分为两个区域,一半是对象区域,一半是空闲区域,如下图所示,新加入的对象都会存放到对象区域,当对象区域快被写满时,就需要执行一次垃圾清理操作。

在垃圾回收过程中:

  1. 首先要对对象区域中的垃圾做标记;
  2. 副垃圾回收器会把这些存活的对象复制到空闲区域中,同时它还会把这些对象有序地排列起来,所以这个复制过程,也就相当于完成了内存整理操作,复制后空闲区域就没有内存碎片了。
  3. 完成复制后,对象区域与空闲区域进行角色翻转,也就是原来的对象区域变成空闲区域,原来的空闲区域变成了对象区域。这样就完成了垃圾对象的回收操作。

 

因为有复制操作所以为了执行效率,一般新生区的空间会被设置得比较小,也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域。为了解决这个问题,JavaScript 引擎采用了对象晋升策略,也就是经过两次垃圾回收依然还存活的对象,会被移动到老生区中。

主垃圾回收器

主垃圾回收器是采用标记 - 清除(Mark-Sweep)的算法进行垃圾回收

标记阶段 遍历调用栈,在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。
清除阶段 清除掉垃圾数据。
整理阶段 让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

全停顿

JavaScript 是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿(Stop-The-World)。了降低老生代的垃圾回收而造成的卡顿,V8 使用增量标记算法,把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,这样当执行上述动画效果时,就不会让用户因为垃圾回收任务而感受到页面的卡顿了。

posted @ 2023-01-03 19:22  哥哦狗子  阅读(106)  评论(0编辑  收藏  举报