一、认识V8引擎
-
V8 是目前一款主流的 JavaScript 执行引擎,目前chrome浏览器和node.js平台都在使用V8引擎去执行 JavaScript 代码,JavaScript 之所以能在这些平台高效去运转,离不开V8引擎的存在
-
V8 采用的是即时编译,之前很多 JavaScript 引擎都要先将源代码转成字节码,然后才能去执行,而V8可以直接将源码可以翻译成当前可以执行的机器码
-
V8 的内存是设有上限的,在64位操作系统上是不超过1.5G,在32位操作系统上是不超过800兆的,V8 本身是为浏览器去制造的,现有的内存大小对于网页应用来说是足够使用的;V8 内部实现的垃圾回收机制也决定了这个内存上限是合理的
二、V8 垃圾回收策略
- 采用的是分代回收的思想,把内存空间分成两类,一类是新生代存储区,一类是老生代存储区,针对不同代采用最高效的 GC 算法
- V8 中常用的 GC 算法:
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
2-1 V8 如何回收新生代对象
左侧主要存放新生代对象,右侧存放老生代对象
-
小空间用于存储新生代对像(64位系统32M,32位系统16M)
-
新生代对象指的是存活时间较短的对象(比如说函数局部作用域名下的变量对象在执行完成之后要回收,这种可以说是新生代对象)
-
新生代对象回收过程主要采用复制算法和标记整理算法,首先会将新生代内存区分为两个等大小空间,就是 From(使用状态空间) 和 To(空闲状态空间),活动对象都会先分配到 From 空间,一旦 From 空间爆满的时候,就会触发 GC 操作,使用标记整理算法,去标记活动对象,然后采用整理操作,让他们位置变得连续,最后的活动对象拷贝到 To 空间中,这个时候 From 空间的活动对象已经有了备份,可以考虑做回收操作了,直接把 From 空间直接释放掉就可以了
-
在将 From 中活动对象拷贝到 To 空间的过程中,可能会出现晋升,晋升的意思就是将新生代的对象移动至老生代;两种情况会出现晋升:
- 如果新生代的对象经过一轮 GC 之后还存活,那就会触发晋升
- 如果在拷贝过程当中 To 空间的使用率超过25%,那也会触发晋升
2-2 V8 如何回收老生代对象
-
老生代存储区在64位系统中是1.4G,在32位系统中700M
-
老生代对象就是指存活时间较长的对象(比如全局作用域中的变量、闭包的变量)
-
老生代对象的回收主要采用了标记清楚、标记整理、增量标记算法,首先使用标记清除完成垃圾空间的回收;当要将新生代对象往老生代存储区移动的时候如果出现空间不足的情况,会采用标记整理算法进行空间的优化;最后会采用增量标记算法进行效率优化
-
用增量标记算法的作用主要是可以让回收操作的 JavaSCript 代码的执行可以交替完成,而不是一口气直接回收完
三、V8引擎工作流程
V8引擎可以认为是浏览器的一个组成部分,用来解析和编译 JavaScript 代码
- 最左侧是浏览器渲染引擎,所以V8引擎只是浏览器渲染引擎里的一个执行js代码的部分
- Scanner 是一个扫描器,把一段纯文本的 JavaSCript 去进行词法分析
- Parser 是一个解析器,解析的过程是一个语法分析的过程,转化成抽象语法树(AST)
- 解析的过程包括预解析(PreParser)和全量解析(Parser),预解析的好处就是跳过那些没有被使用的代码,并且不生成ATS,创建无变量引用和声明scopes(作用域),解析速度会更快;全量解析会解析所有被使用的代码,生成AST,这个时候回生成具体的 scopes 信息、执行上下文、变量引用、声明,并且抛出所有语法错误
- Ignition 是V8提供的解释器,把之前生成的AST转成字节码,可以把这个过程看成预编译
- TurboFan 是V8提供的编译器模块,将字节码转为汇编代码