ESP
记录当前执行状态的指针,指向当前运行状态的执行上下文,当它下移时,会将之前的执行上下文销毁,即清理调用栈的垃圾
调用栈的变量虽然得到了回收,但是堆内的引用类型变量却一直存放在堆中,这时需要JS的垃圾回收器来处理
代际假说
● 因为变量在内存中被访问的时间是很短暂的,所以就使用这样的机制,通过一次访问就变得不可访问
● 不可销毁的对象则停留时间更久
新生代和老生代
● 副垃圾回收器处理新生代的回收
● 主垃圾回收器处理老生代的回收
活动对象是正在使用的对象,非活动对象是需要回收的垃圾
- 标记空间中的活动对象和非活动对象
- 回收非活动对象
- 内存整理,频繁回收垃圾后,会产生大量不连续的空间,这些空间就是内存碎片。如果置之不理的话,会出现内存不足的现象
新生区
新生区划分为对象区域和空闲区域
采用Scavenge 算法来处理
在垃圾回收过程中,首先对对象区域里面的非活动对象做标记,当标记完成后,就进入垃圾处理阶段,副垃圾回收器会把存活的活动对象复制到空闲区域,当复制完毕后,会将对象区域与空闲区域进行翻转,这样就实现了垃圾回收,还可以让新生代两片区域一直重复使用下去
为了执行效率,一般新生区的空间会被设置的很小
对象晋升策略
在对象区域经历两次回收机制后仍然存活的变量会被移动到老生区
老生区
● 对象占用空间大
● 对象存活时间长
采用标记-清除算法来处理
从根元素开始,遍历这组根元素,能达到的元素就是活动对象,没有达到的元素就是垃圾数据
清除过程就是对标记的数据进行销毁
但是多次执行会产生大量不连续的内存碎片,所以又产生了另一种算法:标记 - 整理
让所有活动对象向堆内存的一端移动,然后删掉其余的数据。
全停顿
当执行垃圾回收机制时,需要将JS脚本暂停,待回收完毕才会继续执行,这段过程被称为全停顿
因为老生代的占用空间大,处理时间很长,所以当处理老生代的空间时,会出现较长的卡顿现象,这时候无法对浏览器进行操作,对用户的体验很差,所以用增量标记算法:
将一个完整的垃圾回收任务分解为若干个小任务,穿插在JS的任务中运行,这样就不会因为垃圾回收处理来感受到页面的卡顿了