美文网首页
JS 垃圾回收

JS 垃圾回收

作者: _1633_ | 来源:发表于2020-06-16 09:20 被阅读0次

    在 JS 中 值类型数据存储在 栈空间中,引用类型的数据存储在堆空间中。有些数据被使用之后,就不需要了,我们需要将这些 垃圾数据 进行回收从而释放内存空间,防止这些垃圾数据堆积在 内存中。

    JS 如何 回收垃圾

        在 JS 中,垃圾数据 由 垃圾回收器 来释放,并不需要手动通过代码释放。数据主要存储在栈 和 堆 中,所以我们分两种情况。

    1 调用栈中的数据回收

代码示例

        调用栈详情

调用栈详情

    当执行到 bar() 这段代码的时候,此时的调用栈 情形如图,此时有个一记录当前执行状态的指针(称为 ESP),指向 bar 函数执行上下文, 记录当前 正在执行到的 地方。当 bar 函数执行完, JS 引擎会 销毁 bar 函数执行上下文,指针移动到上一个 执行上下文,也就是 foo 函数的执行上下文,这个 向下移动的操作就是 销毁 bar 函数执行上下文的过程

1 2

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


    2 堆中数据的回收

        当 foo 函数执行完成后, ESP 就指向了 全局执行上下文,bar 函数执行上下文 和 foo 函数执行上下文 都被销毁,但是 堆 当中的 两块内存依然 存储着数据。要回收堆当中的数据,就要用到 JS 中的垃圾回收器了。

        在垃圾回收中有一个重要的概念:代际假说,所有的垃圾回收策略都是建立在该假说之上的。   

        代际假说的两个特点: 1. 大部分对象在内存中存在的时间很短,简单来说,就是很多对象⼀经分配内存,很快就变得不可访问; 2. 不死的对象,会活得更久。

        垃圾回收算法很多,但不是 一种就能处理所有的情况,需要根据不同的情况,采取不同的算法,所以 JS 把 堆分为 新生代老生代 两个区域, 新生代存放的是生存时间短的对象,老生代存放的生存时间久的对象。

        新生代 通常只支持 1-8M 的容量,老生代的容量就大很多。 JS 使用两种不同的垃圾回收器来处理这两块区域的垃圾回收。

        1. 副垃圾回收器,主要处理新生代的垃圾回收;

        2. 主垃圾回收器,主要负责新生代的垃圾回收。

    垃圾回收的工作流程

        1. 标记空间中活动对象(还在使用的对象)和 非活动对象(可以进行垃圾回收的对象);

        2. 回收非活动对象所占的内存,就是在所有标记完成后,统一清除内存中所有被标记为可回收的对象;

        3. 内存整理。通常情况下,在进行垃圾回收后,内存中就会出现 大量不连续的空间,称为 内存碎片。当内存中出现大量 内存碎片后,如果需要分配较大连续内存的时候,就有可能出现内存不足的情况。所以我们需要整理这些 内存碎片(有些垃圾回收器不会产生内存碎片,所以这步骤是可选操作)。

        副垃圾回收器

            主要负责新生区的垃圾回收。通常情况下,大多数小的对象会被分配到 新生区,所以这个区域大小不大,但是操作频繁。

            新生区中 采用 Scavenge 算法,就是把 新生区对半划分为两个区域,一半是对象区域,一半是空闲区域

堆空间

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

            在垃圾回收过程中,首先对 对象区域 内的垃圾做标记,标记完成后,进入垃圾清理阶段, 副垃圾回收器 会把 还在使用的对象 复制到空闲区域,并且有序的排列起来,相当于完成了碎片的整理,复制完成后 空闲区域就没有了内存碎片。

            完成复制后,对象区域 和 空闲区域 角色进行交换,原来的对象区域变成空闲区域,原来的空闲区域变成对象区域,这样就完成了垃圾回收操作,同时这种 角色的对调 能让新生区的这两块区域无限重复使用下去。

            由于 新生区采用了 Scavenge 算法,每次执行清理操作,都要进行一次复制,如果新生区空间设置太大,那么 复制的时间成本会变大,清理时间就会更久,所以 为了执行效率,一般新生区的空间会被设置的比较小。但也就是因为空间小,所以 还在使用的对象很容易存满整个区域,为了解决这个问题, JS 采用了 对象晋升策略,就是 经过两次垃圾回收依然存活的对象,会被移到老生区

        主垃圾回收器

             主要负责老生区的垃圾回收。除了新生区晋升的对象,一些大的对象会被分配到老生区,因此,老生区的对象有两个特点:占用空间大 存活时间长

             由于老生区的对象比较大,采用 Scavenge 算法在复制阶段 会导致 消费大量时间,效率不高,同时还会浪费一半的空间。所以,主垃圾回收器 采用 标记 - 清除(Mark-sweep)的算法进行垃圾回收。

            1. 标记过程阶段,从一组根元素开始,遍历这组根元素,在这个遍历过程中,能到达的元素称为 活动对象,没有到达的元素就可以判断为 垃圾数据

3

            当 bar 函数执行结束,ESP 向下移动执行 foo 函数执行上下文,这时候遍历 调用栈,不会找到 引用 1002地址的遍历,编辑为垃圾数据,1001地址有变量在引用,标记为活动对象。

        2. 垃圾清除过程,当采用 标记-清除法后,会产生 大量不连续的内存碎片,会导致无法分配到足够的连续内存,于是就产生另一种算法:标记-整理(Mark - Compact),这个过程是将 所有 还在使用的对象 都移动到一端,然后直接清除掉边界之外的内存。

标记清楚和标记整理

全停顿

    V8 使用 副垃圾回收器 和 主垃圾回收器处理垃圾回收, 不过 JS 是单线程,一旦执行 垃圾回收算法,其他 JS 脚本都会暂停,等待垃圾回收结束才恢复执行,我们称这种行为 为 全停顿(Stop-The-World)。

        在 新生区 中的垃圾回收,因其空间小,且 活动对象少,所以全停顿的影响不但,但是 老生区不一样。如果垃圾回收 占用时间越久,那么这个过程中,主线程会被完全占用,不能处理其它事情,比如 页面正在执行 动画,因为垃圾回收器,导致 动画在一段时间无法执行,会使页面出现卡顿现象。

全停顿

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

增量标记

            采用 增量标记,能将一个完整的垃圾回收任务拆分成很多小任务,这些小任务执行时间较短,可以穿插在其他 JS 任务中执行,比如 动画效果,就不会使页面出现卡顿。


总结

    JS 中的 简单数据类型 和 引用数据类型 分别存放在 栈 和 堆 中;

    栈中的数据 通过 ESP 向下移动 销毁保存在 栈中的数据;

    堆分为两块区域:新生区 和 老生区,主要通过 副垃圾回收器 和 主垃圾回收器 处理垃圾;

    副垃圾回收器 采用 Scavenge 算法 将 新生区分为 对象区域 和 空闲区域,通过两个区域不断替换角色来无限使用;

    主垃圾回收器 采用标记清除法,标记整理法,增量标记法 进行垃圾回收;

    无论 主 副垃圾回收器,流程都是 标记 ----  清除 ----- 整理 这几个步骤。

相关文章

  • JS 垃圾回收机制

    从下面这几个方面简单介绍:JS 垃圾回收机制,几种?weakMap, WeakSet JS 垃圾回收机制, 标记清...

  • JavaScript内存管理

    JS内存回收 JS 有自动垃圾回收机制,就是找出那些不再继续使用的值,然后释放其占用的内存。 垃圾回收算法: 引用...

  • JS内存空间详解(摘录)

    js具有自动垃圾回收机制,垃圾回收的方法有两种:标记清除法、计数清除法 垃圾回收的实现算法: 垃圾回收器创建一个"...

  • 垃圾回收

    js的垃圾回收 原文:https://segmentfault.com/a/1190000018605776 垃圾...

  • js内存管理

    导读:js是高级语言,有自带的垃圾回收器,一般认为js开发可以不用关心内存管理。然而这是错误的。 js垃圾回收算法...

  • 闭包的理解。

    js的垃圾回收机制 当一个函数执行完,js引擎会回收不再使用的内存,闭包通过这个作用域的引用,阻止了垃圾回收。 什...

  • 垃圾回收

    垃圾回收一共分两种:栈中的垃圾回收和堆中的垃圾回收 栈中的垃圾回收 JS 引擎有一个记录当前执行状态的指针,称为 ...

  • Javascript垃圾回收机制

    简介 JS自带一套内存管理引擎,负责创建对象、销毁对象,以及垃圾回收。这期探讨一下垃圾回收机制。垃圾回收机制主要是...

  • js垃圾回收

    像C语言这种偏底层的高级语言,是需要程序员手动申请和释放内存的,典型的用了 malloc 和 free 两种方法。...

  • js 垃圾回收

    js 中垃圾回收机制 引用内存会一直存在,直到不被使用标记,人为清除如:设为 null、浏览器关闭、页面关闭 局部...

网友评论

      本文标题:JS 垃圾回收

      本文链接:https://www.haomeiwen.com/subject/qeygtktx.html