V8——JavaScript执行引擎,垃圾回收策略、算法

285 阅读3分钟

V8认识

  • 是一款主流的JavaScript执行引擎
  • V8采用即时编译
  • V8内存设限,64位系统不超过1.5G,32位系统不超过800M。

V8垃圾回收策略

  • 采用分代回收的思想
  • 内存分为新生代、老生代
  • 针对不同对象采用不同算法 image.png

V8中常用GC算法

  • 分代回收
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量

V8如何回收新生代存储区对象

内存分配

image.png

  • V8内存空间一分为二,左边为新生代存储区,新生代存储区又分为两个存储区,右边为老生代存储区
  • 小空间用于存储新生代对象(32M | 16M,对应64位系统和32位系统)
  • 新生代指的是存活时间较短的对象

新生代对象回收实现

  • 回收过程采用赋值算法 + 标记整理
  • 新生代内存区分为两个等大小空间
  • 使用空间为From,空闲空间为To
  • 活动对象存储于From空间
  • 标记整理后将活动对象拷贝至To空间
  • From与To交换空间完成释放

回收细节说明

  • 拷贝过程中可能出现晋升
  • 晋升就是将新生代对象移动到老生代
  • 一轮GC还存活的新生代对象需要晋升
  • To空间的使用率超过25%需要晋升

V8如何回收老生代存储区对象

  • 64位操作系统1.4G,32位操作系统700M
  • 老生代对象就是指存活时间较长的对象,比如全局变量,或者闭包产生的变量

老生代对象回收实现

  • 主要采用标记清除、标记整理、增量标记算法
  • 首先使用标记清除完成垃圾空间的回收,主要是用标记清除算法,虽然会产生空间碎片化问题,但是这个算法速度更快,性能更好
  • 采用标记整理进行空间优化,当新生代对象往老生代存储区移动,也就是晋升,且老生代存储区出现内存空间不足的时候就会触发标记整理算法
  • 采用增量标记进行效率优化

问题

  1. 为什么老生代存储区不使用与新生代存储区一样的方法? 因为老生代存储区比较大,如果将空间一分为二将会浪费几百兆的空间;存放对象数据比较多,也不适合使用复制算法
  2. 为什么新生代存储区要将空间一分为二,这样不是浪费了空间? 因为新生代存储区所占空间较小,划分为两个空间造成的空间浪费影响与之带来的回收效率相比,可以说是利大于弊,可以说是使用空间来换取时间

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

image.png 增量标记算法就是将标记的过程拆分,与程序执行交替运行,当标记阶段完成之后就进行清除操作完成回收。这个过程看似程序停顿了很多次,但是这些停顿所占的时间都是不影响视觉的,因为在使用非增量标记算法回收1.5G的垃圾时,V8引擎最多只使用了一秒的时间完成回收。