深入理解浏览器垃圾回收机制(V8)

  • 定义
    栈用来在函数执行时存储保存执行上下文环境,我们一般也称调用栈,如基本类型的变量,引用类型的引用地址等都保存在栈中。执行到当前函数时进行入栈,执行完毕进行出栈。
  • 回收方式
    有一个记录当前执行状态的指针(称为 ESP)指向活动栈,函数执行完毕,esp下移到后一节点,销毁当前函数执行上下文。新的函数执行上下文入栈直接覆盖掉销毁的空间即可 .
function test() {
  const a = { name: 'a' };
  function showName() {
    const b = { name: 'b' };
  }
  showName();
}
test();

在这里插入图片描述

  • 定义
    对象的值等大数据保存在堆中。

  • 回收方式
    使用 JavaScript 中的垃圾回收器进行回收,通过标记的方式进行回收。
    采用 可访问性(reachablility)算法来判断堆中的对象是否为活动对象。这个算法其实就将一些GC Root 作为初始存活对象的集合,从 GC Root 对象触发,遍历 GC Root中的所有对象

    • 能够通过 GC Root(全局 wimdow 、dom树、栈上的变量、回收非活动对象占据的内存)遍历到的对象会被认为是可访问的,我们将其标记为活动对象,必须保留
    • 如果一个对象无法通过 GC Root 遍历到,那么就认为这个对象是不可访问的,可能需要被回收,并标记为非活动对象

堆的垃圾回收

在垃圾回收领域有一个代际假说的概念,大致意思就是数据分为生命周期短的和长久的。
根据代际假说,v8对堆的数据保存分为新生代区域老生代区域两大块。这两区域的垃圾回收是不同的,分别为副垃圾回收器主垃圾回收器

  • 新生代区域
    存储空间小,不能存放大对象

  • 老生代区域
    空间大,存活时间长。新生代经过2次GC仍存活的的变量

  • 副垃圾回收器
    通过将新生代区域平分为2块区域:对象区空闲区。当活动区中内存满时启动垃圾回收,遍历对象进行垃圾标记,将活动的对象复制到空闲区,移动到空闲区的对象是按顺序来的,因此不用去整理。处理完后,将对象区空闲区翻转,完成垃圾回收。复制操作需要时间成本,因此为了效率,空间一般设置的很小。空间小,容易填满,因此又采用了对象晋升策略,经过两次垃圾回收依然存活的对象就会被移动到老生区

  • 主垃圾回收器
    采用标记-清除(Mark-Sweep)的算法进行垃圾回收。解决标记-清除空间不连续引入标记-整理(Mask-Compact),标记完后,先将所有存活的对象向一端移动,然后直接清理掉这一端以外的内存。

优化效率

  • 并发标记: 在主程序运行阶段,并发的对变量进行标记处理,防止中断js主线程。笔辩主线程、辅助线程同时修改同一对象,需实现读写锁等功能。

  • 并行整理:进行整理时占用主线程,在此基础上,启动多个辅助线程一起处理,加快速度。

  • 增量整理:由于在整理时是占用的主线程,会阻塞js运行,因此通过增量的方式,将一次处理分成多个小任务处理,减小对用户的影响。js运行与标记相互交叉,防止变量引用在a,b之间变换,造成标记失败,使用黑白灰三色标记法进行处理。

  • 黑白灰三色标记

    • 黑:节点以及子节点已处理完
    • 灰:正在处理的节点。黑节点的子节点不能为白节点,直接置灰(写屏障)
    • 白: 非活动对象,等待回收
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章