JS垃圾回收机制主要分为对栈和堆两种存储数据的回收:
一、栈中数据回收
1) 首先我们需要了解一个概念ESP指针:是指针寄存器的一种,用于堆栈指针,主要用来标记当前活动位置,简单就是标记当前代码执行位置
2) 当我们执行一个函数时除了会有存储的变量外,还会有一个执行上下文;此时ESP指针则会指向当前上下文,当该方法执行完毕,则ESP指针跳转到下一个函数的上下文,
同时将上一个函数的上下文弹出,可以进行销毁
3) JS 引擎是通过向下移动 ESP 指针来销毁存放在栈空间中的执行上下文。
二、堆数据回收
1)V8引擎会把堆分为新生代和老生代两个区域,其中新生代存放的是生存时间短的对象,老生代中存放的则是生存时间久的对象,
其中副垃圾回收器主要负责新生代的垃圾回收,主垃圾回收器负责老生代垃圾的回收
2) 垃圾的工作流程:主、副垃圾回收器都遵循同一套执行流程:
第一步:标记空间中活动对象(还在使用的对象)和非活动对象(可以进行垃圾回收的对象)
第二步:标记完成后,统一回收内存中被标记为可回收的对象
第三步:做内存整理,由于频繁回收后,内存中则会留下大量不连续的空间可以称之为内存碎片,当需要分配大的连续内存时,
就有可能出现内存不足的情况,所以需要对这些碎片做整理,但是副垃圾回收器不会产生内存碎片
3)副垃圾回收器工作原理:
1. 副垃圾回收器主要负责新生代的垃圾回收,一般小的对象会被分配到新生区,所以这个区域虽然不大,但是回收比较频繁。
2. 新生代中使用Scavenge算法处理,主要是把新生代空间分为两个区域,一半是对象区域,一半是空闲区域。
3. 新加入的对象会被存放到对象区域中,当对象区域快被写满时,就需要执行一次垃圾回收操作。
4. 首先对对象区域中的垃圾做标记,标记完成后,就倾入垃圾清理阶段,副垃圾回收器会把这些存活的对象复制到空闲区域中,
同时还会把这些对象有序的排列起来,所以整个复制过程也就是一个内存整理的过程,不会形成内存碎片。
5. 复制完成后,对象区域和空闲区域角色就会互换,空闲变为对象,对象变为空闲,这种角色互换的方式可以让新生代的内存区域无限重复使用下去
4)主垃圾回收器工作原理:
1. 主垃圾回收器主要负责老生区中的垃圾回收,数据来源除了新生区中的晋升对象,还会把一些大的对象直接分配到老生区,
所以老生区的数据一般是对象占用空间大,存活时间长。
2. 由于对象较大,所以采用Scavenge算法复制这些对象消耗时间久会比较多,降低回收效率不说还会浪费一半空间,
3. 采用标记-清除算法的过程中,标记阶段是从一组根元素开始,递归遍历这组根元素,能到达的元素称为活动对象,无法到达的则是垃圾数据。
4. 清理掉垃圾数据
5. 清除垃圾数据后会产生内存碎片,通过标记-清理算法将活动对象向一端移动排序,避免内存碎片
注:部分文章会说采用的是引用计数算法执行的,但是由于相互引用无法释放的问题,所以该方法已经被弃用。
三、常见的内存泄漏问题
1) 定义的全局变量没有使用
2) 被遗漏的定时器没有及时释放
3) 闭包使用不当,导致对象没有及时释放
4) 对象之间的循环引用
5)DOM删除了,注册的事件没有释放
标签:标记,对象,回收,JS,区域,内存,垃圾 From: https://www.cnblogs.com/codeOnMar/p/17334146.html