2024.02 v8学习
V8运行环境
node环境和浏览器环境
浏览器为v8提供了基础的消息循环系统、全局变量、web api。v8的核心是实现了ecmascript标准、还提供了垃圾回收器等。
在chrome中,只要打开一个渲染进程,渲染进程便会初始化v8,同时初始化堆空间和栈空间。
栈空间主要是用来管理js函数调用的,栈是内存中连续的一块空间,在函数调用过程中,涉及到上下文相关的内容都会存放在栈上。当函数执行结束,函数的执行上下文你便会被销毁掉。
栈空间是连续的,栈中每个元素的地址都是固定的,因此栈空间的查找效率很高,v8对栈空间的大小做了限制,如果函数调用层过深,那么v8就有可能抛出栈溢出的错误。
堆空间是一种树形的存储结构,用来存储对象类型的离散的数据。js中除了原生类型数据,其他的都是对象类型,诸如函数、数组,在浏览器中还有 window 对象、document 对象等,这些都是存在堆空间的。
宿主在启动v8过程中,会同时创建堆空间和栈空间,再继续往下执行,产生的新数据都会存在这两个空间中。
初始化完存储空间后,开始初始全局上下文和全局作用域。
v8用执行上下文来维护执行当前代码所需要的变量声明、this指向等。
执行上下文包含:变量环境、词法环境和this关键字。
全局执行上下文再v8生存周期内是不会被销毁的,会一直保存在堆中,这样当下次再需要全局变量和函数时就不需要再创建了。
当v8调用一个函数时,就会进入函数的执行上下文,这时候全局执行上下文和当前的函数执行上下文就形成了一个栈结构。
V8 还需要有一个主线程,用来执行 JavaScript 和执行垃圾回收等工作。V8 是寄生在宿主环境中的,它并没有自己的主线程,而是使用宿主所提供的主线程,V8 所执行的代码都是在宿主的主线程上执行的。
汇编语言,只是将机器语言做了简单的编译,通常被用在底层硬件操作和高要求的程序优化场合。
机器语言,是机器能直接识别的程序语言或指令代码,无需经过翻译,不经翻译即可为机器直接理解和接受的程序语言或指令代码。
cpu可以通过内存地址从内存中读取数据,往内存中写入数据。
内存是一个临时存储数据的设备,断电后内存的数据就会消失。
二进制代码被装载进内存,CPU便可以从内存中取出一条指令,分析该指令,最后执行该指令,直至指令执行完成。
pc寄存器,保存了将要执行的指令地址。它保存了将要执行的指令地址,当二进制代码被装载进了内存之后,系统会将二进制代码中的第一条指令的地址写入到 PC 寄存器中,到了下一个时钟周期时,CPU 便会根据 PC 寄存器中的地址,从内存中取出指令。 PC 寄存器中的指令取出来之后,系统要做两件事:
- 将下一条指令地址更新到PC寄存器
- 分析指令,并识别出不同类型的指令,以及各种获取操作数的方法。
分析完成后就要执行指令了。
通用寄存器是CPU中用来存放数据的设备,不同处理器中寄存器的个数也是不一样的,因为CPU访问内存的速度很慢。
通用寄存器容量小,读写速度快,内存容量大,读写速度慢。
寄存器通通常用来存放数据或内存中某块数据的地址,可以存数据,也可以存指针。
指令类型
加载的指令,其作用是从内存中复制指定长度的内容到通用寄存器中,并覆盖寄存器中原来的内容
存储的指令,和加载类型的指令相反,其作用是将寄存器中的内容复制内存某个位置,并覆盖掉内存中的这个位置上原来的内容
更新指令,其作用是复制两个寄存器中的内容到 ALU 中,也可以是一块寄存器和一块内存中的内容到 ALU 中,ALU 将两个字相加,并将结果存放在其中的一个寄存器中,并覆盖该寄存器中的内容
CPU 执行机器代码的逻辑非常简单,首先编译之后的二进制代码被加载进内存,然后 CPU 就按照指令的顺序,一行一行地执行。
在执行指令的过程中,CPU 需要对数据执行读写操作,如果直接读写内存,那么会严重影响程序的执行性能,因此 CPU 就引入了寄存器,将一些中间数据存放在寄存器中,这样就能加速 CPU 的执行速度。
有了寄存器之后,CPU 执行指令的操作就变得复杂了一点,因为需要寄存器和内存之间传输数据,或者寄存器和寄存器之间传输数据。我们通常有以下几种方式来使用寄存器,这包括了加载指令、存储指令、更新指令。通过配合这几种类型的指令,我们就可以实现完整的程序功能了。
在寄存器中保留函数地址,在内存中保留函数的栈帧指针,每个栈帧对应着一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。
栈空间是有限的,连续的。