三、JS引擎V8中的垃圾回收机制

性能优化GCV8垃圾回收

# 认识V8

  • V8 —— 是 Google 发布的主流的开源 JavaScript 引擎,采用 C++ 编写。采用即时编译,直接翻译成机器语言,并且使用了如内联缓存(inline caching)等方法来提高性能。有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序。

  • V8内存设限:

    • 64bit操作系统上不超过1.5G
    • 32bit操作系统上不超过800M

    这么设限为了浏览器使用内存足够,内部还有垃圾运行机制,时间也在用户感知的合理范围

  • 目前V8垃圾回收采用增量标记算法需要50ms,采用非增量标记算法需要1s

# V8垃圾回收策略

程序的使用过程中,可以分为 原始类型数据对象类型数据

原始数据都是由程序语言自身控制的,这里的回收还是指主要存活在堆区的对象数据,这个过程是离不开内存操作的,V8也是对内存做了上限,那在这种情况下是如何对垃圾进行回收的?

  • 采用分代回收的思想
  • 内存分为新生代存储区、老生代存储区
  • 针对不同代采用不同的算法

所以V8中会用到更多的GC算法,这里对GC算法不懂的还有这篇文章中说到的标记清除、整理等算法详细介绍在这篇文章中,此文章不再进行赘述

GC —— 垃圾回收机制认识与算法详解 (opens new window)

# V8常用的GC算法

  • 分代回收 (一定会用)
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量 (提高效率用)

# V8的分代回收

  • 新生代 —— 就是指存活时间较短的对象,例如:一个局部作用域中,只要函数执行完毕之后变量就会回收。
  • 老生代 —— 就是指存活时间较长的对象,例如:全局对象,闭包变量数据。

# V8的内存分配

V8内存空间一分为二,分为新生代存储区和老生代存储区,如图:

  • 左边小空间用于存储新生代对象
    • 64bit操作系统上不超过32M
    • 32bit操作系统上不超过16M
  • 右边较大空间用于存储老生代对象
    • 64bit操作系统上不超过1.6G
    • 32bit操作系统上不超过700M

# 新生代对象回收

# 主要使用算法

采用复制算法 + 标记整理算法

# 回收过程

新生代内存区分为两个等大小空间,使用空间为From,空闲空间为To

如果需要申请空间使用,回收步骤如下:

  1. 首先会将所有活动对象存储于From空间,这个过程中To是空闲状态。
  2. From空间使用到一定程度之后就会触发GC操作,这个时候会进行标记整理对活动对象进行标记并移动位置将使用空间变得连续,便于后续不会产生碎片化空间。
  3. 将活动对象拷贝至To空间,拷贝完成之后活动空间就有了备份,这个时候就可以考虑回收操作了。
  4. From空间完成释放,回收完成
  5. FromTo名称进行调换,继续重复之前的操作。

总结就是:
使用From -> 触发GC标记整理 -> 拷贝到To -> 回收From -> 名称互换重复之前

# 晋升

拷贝的过程中某个对象的指代在老生代空间,就可能出现晋升。 晋升就是将新生代对象移动至老生代。

什么时候触发晋升操作?

  1. 当存储的对象比新生代的空间大时,会直接存到老生代区域。
  2. 在从Form拷贝到To的时候,会根据地址判断复制的对象是否已经经历过了一轮GC,已经被复制过一次的新生代对象就会晋升。
  3. 在拷贝过程中,To空间的使用率超过25%,将这次的活动对象都移动至老生代空间。

为什么是限制To的使用率呢?

将来回收操作是要把From空间的内容拷贝到To空间中进行交换,如果To的使用率太高,变成From之后新的对象就存不进去了。

# 回收老生代对象

# 主要使用算法

主要采用标记清除 (首要) 、标记整理、增量标记算法

  • 标记清除:首先会采用标记清除法,虽然使用标记清除会有空间碎片化的问题,但是标记清除提升的速度是很快的。
  • 标记整理:其次在晋升的时候且老生代区域的空间也不够容纳的时候,就会采用标记整理进行 空间优化
  • 增量标记:回收的过程,会使用增量标记将一整段的垃圾回收操作标记拆分成多个小段完成回收,主要是为了实现程序和垃圾回收的交替完成,这样进行 效率优化 带来的时间消耗更加的合理。

之前标记清除和整理的原理都在GC那篇文章中解释,这里就详情看看增量标记是如何工作的?

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

看图可以将垃圾回收分成两个部分,一个是程序的执行,一个是垃圾的回收。当垃圾回收的时候其实会阻塞程序的执行,所以中间会有空档期。

# 新生代 VS 老生代

  • 新生代区域垃圾回收使用空间换时间
    • 主要采用复制算法,要有空闲空间存在,当然新生代本身空间小,分出来的复制的空间更小,所以浪费这点空间换取时间的效率是微不足道的
  • 老生代区域垃圾回收不适合复制算法,老生代空间大一分为二,会造成一半的空间浪费,存放数据多复制时间长。
更新时间: 2021-09-16 11:57