简介

V8基础知识学习笔记。

语言分类

按语言的特性

静态语言: 使用之前需要知道变量类型。
弱类型语言: 支持隐式类型转换。JS 是属于弱类型动态语言。

按语言的执行流程

编译型语言: 需要经过编译器的编译过程,并且编译之后会直接保留机器能读懂的二进制文件,这样每次运行程序时,都可以直接运行该二进制文件,而不需要再次重新编译了。比如 C/C++、GO 等都是编译型语言。

解释型语言: 由解释型语言编写的程序,在每次运行时都需要通过解释器对程序进行动态解释和执行。比如 Python、JavaScript 等都属于解释型语言。

数据存储

栈和堆

基本类型: 存储在栈中。包括: Boolean、String、Undefined、Null、Number。
引用类型: 存储在堆中。包括: Object、Array、Function。
可枚举属性: 基本类型的原型属性是可枚举的,如 Boolean、String、Undefined、Null。
不可枚举属性: 基本包装类型的原型属性是不可枚举的,如 Object、Array、Function、Number。

为什么需要 "堆" 空间?

因为 JavaScript 引擎需要用栈来维护程序执行期间上下文的状态, 
如果栈空间大了话,所有的数据都存放在栈空间里面,
那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。

比如某个函数执行结束了,JavaScript 引擎需要离开当前的执行上下文,
只需要将指针下移到下个执行上下文的地址就可以了,
而此函数执行上下文【栈区空间】全部回收。

垃圾回收

栈垃圾回收

调用栈中有一个记录 当前执行状态的指针(称为 ESP),指向调用栈中 当前执行上下文,

当一个 执行上下文 结束之后,JavaScript 引擎会通过向下移动 ESP,

这个下移操作就是销毁 当前执行上下文 过程。

堆垃圾回收

V8 中会把堆分为新生代和老生代两个区域:
新生代中存放的是生存时间短的对象,
老生代中存放的生存时间久的对象。
副垃圾回收器,主要负责新生代的垃圾回收。
副垃圾回收器采用: Scavenge 算法
主垃圾回收器,主要负责老生代的垃圾回收。
主垃圾回收器采用: 标记 - 清除(Mark-Sweep)、标记 - 整理(Mark-Compact)、增量标记(Incremental Marking)

解释器和编译器

V8 是如何执行一段 JavaScript 代码的?

1. 解析器: 根据代码生成抽象语法树(AST)和执行上下文

2. 解释器: 根据 AST 生成字节码

3. 编译器: 将 字节码 编译成 机器码,然后执行代码

为什么 V8 使用字节码而放弃机器码?

其实一开始 V8 并没有字节码,而是直接将 AST 转换为机器码,由于执行机器码的效率是非常高效的,所以这种方式在发布后的一段时间内运行效果是非常好的。

但是随着 Chrome 在手机上的广泛普及,特别是运行在 512M 内存的手机上,内存占用问题也暴露出来了,因为 V8 需要消耗大量的内存来存放转换后的机器码。

为了解决内存占用问题,V8 团队大幅重构了引擎架构,引入字节码,并且抛弃了之前的编译器,最终花了将进四年的时间,实现了现在的这套架构。

参考资料

powered by Gitbook该文件修订时间: 2023-05-18 11:38:33

results matching ""

    No results matching ""