概述
1、什么是v8?
V8是JavaScript虚拟机的一种,可以理解为一个翻译程序,将人类能够理解的编程语言翻译成机器能够理解的机器语言。(用来执行js代码)
市面上有多种JavaScript引擎:spiderMonkey、V8、JavaScriptCore
在v8之前,所有JavaScript虚拟机都是采用解释执行的方式。V8引入了即时编译,混合编译执行和解释执行两种手段,给JavaScript的执行速度带来极大的提升。
V8还引入了惰性编译、内联缓存、隐藏类等机制。进一步优化的JavaScript的编译执行速度。
2、高级语言为什么先编译后执行(CPU怎么执行机器代码的)?
可以把CPU看成是非常小的运算机器。我们可以通过二进制指令和CPU进行通信。比如给CPU发出
1000100111011000
的二进制指令,这条指令的意思是将寄存器中的数据移到另一个寄存器。
CPU
只能识别二进制指令
所以需要一个汇编编译器,将汇编代码转为机器代码。
但是汇编语言依然是复杂繁琐的。
首先,不同的CPU有着不同的指令集。所以你需要为每种架构的CPU编写特定的汇编代码。
在编写汇编代码时,我们需要了解和处理器架构相关的硬件知识。比如需要寄存器、内存、操作CPU等。
因此需要一种屏蔽计算机架构细节的语言。能适应多种CPU的架构语言。比如C、C++、JavaScript、Java、C#、python
和汇编语言一样,处理器不能识别高级语言。通过两种方式来执行这些代码。
第一种是解释执行。
需要将输入的源代码通过解析器编译成中间代码,之后直接使用解释器解释执行中间代码,然后直接输出结果。
第二种是编译执行。
也需要将源代码转为中间代码,然后编译器再将中间代码编译成机器代码。通常编译成的机器代码是二进制形式存在的。需要执行这段程序直接执行二进制文件就可以了。
还可以使用虚拟机将编译后的机器代码保存在内存中,直接执行内存中的二进制代码。
3、v8是如何执行一段JavaScript代码的?
其主要核心流程是编译和执行两步。首先将JS代码转换为低级中间代码或者机器能够理解的代码,然后再执行并输出结果。
可以把V8看做是虚拟机,模拟实际计算机的各种功能来实现代码的执行。
比如:模拟实际计算机的CPU、堆栈、寄存器等。
V8
采用混合编译执行和解释执行两种手段。称为JIT(just in time)
因为这两种各有各自的优缺点。解释执行的启动速度快,但执行速度慢。而编译执行的启动速度慢,执行速度快。
首先,在v8启动执行js之前,需要准备执行时的准备环境,包括堆空间、栈空间、执行上下文、消息循环系统、内置函数等。
这
些内容都需要在执行JavaScript过程中需要的。
比如:
JavaScript全局执行上下文就包含了执行过程中的执全局信息,比如内置函数、全局变量等。
全局作用域就包含了一些全局变量,在执行过程中数据都需要保存在内存中。
V8
采用了堆和栈的内存管理方式,所以v8还需要初始化内存中的堆和栈结构。
另外还需要初始化消息循环系统,它如同v8的心脏,不断接受消息,并处理。
基础环境准备好后,接下来就可以向v8提交需要执行的代码了。
结构化源代码,生成抽象语法树(AST),即便于v8理解的结构。同时生成相关的作用域,作用域中存放变量。
接下来生成字节码。是介于机器码和AST的中间代码。
解释器可以执行解释执行字节码。
在解释执行的过程中,如果
发现某一段代码被重复多次执行,那么就会这段代码标记为热点代码。
V8会将这段字节码丢给优化编译器,优化编译器会把字节码编译为二进制代码,然后再对二进制代码进行优化,优化后的二进制代码执行效率会大幅提升。
但是和静态语言不同,JavaScript是动态语言,对象的结构和属性是可以在运行期间任意修改的,而优化后的代码只针对某种固定结构,一旦在执行过程中,对象的结构被动态修改了,那么优化后的代码势必变成无效的代码。
这时候就要优化编译器执行反优化操作,下次执行就退回解释器解释执行。
总结:
1
、初始化基础环境;
2、解析源码生成 AST 和作用域;
3、依据 AST 和作用域生成字节码;
4、解释执行字节码;监听热点代码;
5、优化热点代码为二进制的机器代码;
6、反优化生成的二进制机器代码。
4、v8为什么又要引入字节码?
机器代码缓存
从图中可以看出,编译所消耗的时间和执行所消耗的时间是差不多的,试想一下,如果在浏览器中再次打开相同的页面,当页面中的 JavaScript 文件没有被修改,那么再次编译之后的二进制代码也会保持不变, 这意味着编译这一步白白浪费了 CPU 资源,因为之前已经编译过一次了。
这就是 Chrome 浏览器引入二进制代码缓存的原因,通过把二进制代码保存在内存中来消除冗余的编译,重用它们完成后续的调用,这样就省去了再次编译的时间。
V8
使用两种代码缓存策略来缓存生成的代码。
- 首先,是 V8 第一次执行一段代码时,会编译源 JavaScript 代码,并将编译后的二进制代码缓存在内存中,我们把这种方式称为内存缓存(in-memory cache)。
- 将代码缓存到硬盘上,这样即便关闭了浏览器,下次重新打开浏览器再次执行相同代码时,也可以直接重复使用编译好的二进制代码。
- 时间问题:编译时间过久,影响代码启动速度;
- 空间问题:缓存编译后的二进制代码占用更多的内存。
- 解决启动问题:生成字节码的时间很短;
- 解决空间问题:字节码占用内存不多,缓存字节码会大大降低内存的使用;
- 代码架构清晰:采用字节码,可以简化程序的复杂度,使得 V8 移植到不同的 CPU 架构平台更加容易。
最后
以上就是鲤鱼万宝路为你收集整理的如何将二进制机器码转换成汇编指令_v8是如何执行一段JavaScript代码的?的全部内容,希望文章能够帮你解决如何将二进制机器码转换成汇编指令_v8是如何执行一段JavaScript代码的?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复