前端浏览器垃圾回收

529 阅读4分钟

引用计数工作原理和优缺点

  1. 引用计数工作原理:通过设置引用数,判断当前引用数是否为0,再根据引用关系改变时修改引用数字,当引用数字为0时立即进行回收。(其实就是是否被引用,如果无其他地方引用则直接进行回收,如果其他地方还在引用则不会进行回收)
  2. 引用计数优缺点:
    1. 优点:
      • 发现垃圾时立即回收
      • 最大限度减少程序暂停(当执行内存即将爆满时,引用计数算法是实时的监控引用数字为0对象,就会立即回收计数为0对象,并且释放内存)
    2. 缺点:
      • 无法回收循环引用的对象
      • 时间开销大(由于监控当期引用数值时刻的变化)
function fn(){
  const obj1={}
  const obj2={}
  obj1.name=obj2
  obj2.name=obj1
  return '11111'
}
fn()
循环引用:由于fn函数再运行完成后,会进行回收,当回收obj1时,发现obj1被引用,导致无法进行回收;当回收obj2时发现obj2被引用,导致无法进行回收

标记整理算法的工作流程

标记清除算法实现原理:

  1. 核心思想:分标记和清除二个阶段完成 a.遍历所有对象找到标记活动对象;第一阶段 b.遍历所有对象清除没有标志对象(会抹掉第一阶段的标记对象的标记便于GC操作下次正常工作);第二阶段 c.回收相应的空间
  2. 标记清除算法优缺点
    1. 优点:解决循环引用无法回收
    2. 缺点:形成空间碎片化(由于回收时垃圾对象在地址上时是不连续的,在进行回收后,导致释放的空间存在各个地方,在使用的时候,有时无法按照要求进行匹配,新进的对象会大小不一,不能使内存空间最大化使用)

标记整理算法实现原理:

  1. 标记整理可以看做是标记清除的增强
  2. 标记阶段的操作和标记清除一致
  3. 清除阶段会先执行整理,移动对象位置 执行标记操作时会把活动的对象进行标记,再进行整理操作,进行位置改变,会将活动对象进行移动,将地址变成连续,将非活动对象和空空间进行回收

v8垃圾回收

v8垃圾回收策略

  1. 采用分代回收思想(将内存空间分成新生代、老生代)
  2. 针对不同对象(新生代和老生代)采用不同算法(新生代对象存储采用具体的GC算法;老生代对象存储采用具体算法)

v8中常见GC算法

  1. 分代回收
  2. 空间复制
  3. 标记清除
  4. 标记整理
  5. 标记增量

新生代对象回收

  1. 新生代存储空间为(32M|16M)
  2. 新生代指的是存活时间较短的对象

新生代对象回收实现

  1. 新生代对象回收过程采用复制算法+标记整理
  2. 新生代内存区分为二个等大小的空间
  3. 使用空间为From,空闲空间为To
  4. 代码在执行时需要申请空间使用首先会将所有的变量对象分配到from空间中
  5. 标记整理后将活动对象拷贝至To
  6. From与To交换空间完成释放(释放所有的From空间)

回收细节说明

  1. 拷贝过程中可能出现晋升(拷贝时发现某一个变量对象所使用的空间(新生代对象中的变量)在老生代对象中也出现)
  2. 晋升就是将新生代对象移动至老生代
    • 一轮GC还存活的新生代需要晋升(判断依据)
    • To空间的使用率超过25%(判断依据)

v8回收老生代对象

  1. 64位操作系统中为1.4G,32位操作系统700M
  2. 老生代对象就是指存活时间较长的对象(例如在全局作用域、闭包中的变量)

老生代对象回收实现
主要采用标记清除、标记整理、增量标记算法

  1. 首先使用标记清除完成垃圾空间的回收
  2. 采用标记整理进行空间优化(什么时候使用标记整理:如果发现新生代存储区域的内容往老生代存储区域移动时,发现老生代存储的空间无法满足需要移动的新生代存储对象)
  3. 采用增量标记进行效率优化

标记增量如何优化垃圾回收

  1. 增量标记算法在代码执行完成后,垃圾回收和程序运行交替
  2. 工作原理:先找到第一层的可达对象进行标记,再次让程序运行,找到第二层可达对象后,程序停止运行,进行标记,依次进行交替执行,当所有的可达对象标记完成后,程序最后一次执行,进行清除操作