参考:

b站:编译原理-哈工大

知乎:v8架构是如何一步步演进成如此成熟的架构的

cocos论坛:开挂了:iOS 14.2 开启 JIT 支持,大幅提升 JS 性能!

python变成基础:编译型语言和解释型语言的区别

 

看到cocos论坛说ios不支持JIT,JIT是即时编译技术,在运行时将代码编译成机器码,说起JIT要从编译说起...

编译原理

cpu只能识别机器码,就是0和1,所以使用c++、java、javascript、typescript等语言写的代码最终都要变成机器码,这个高级语言变成机器语言的过程叫编译。

0和1就是二进制,1高电平,0低电平,高低电平以一定组合输入cpu针脚,形成了可识别的数据。以前做单片机开发就用示波器调试高低电平组成的驱动程序。

早期也有三进制等更多进制,但是状态越多,越容易受到干扰,每秒百万次变化的晶体管会让这个问题变得严重,所以使用了0和1的二进制。

 

编译型和解释型

不同语言变成机器码的方式不同,分成了编译型和解释型语言。

编译型:C语言、C++、Golang、Pascal(Delphi)、汇编等

解释型:Python、JavaScript、PHP、Shell、MATLAB 等

 

编译型语言

1. 一次编译,无限运行。例如c语言编译成windows下exe文件,一次性将源码编译成机器码,exe文件包含了机器码,无需再次编译,直接运行即可。

1.可执行程序不能跨平台。不同操作系统对不同执行文件要求不同,不能将windows下执行文件拿到linux下运行。

2.代码不可跨平台。不同平台支持的函数、变量、类型不同。例如c语言windows下是Sleep()单位毫秒,Linux下是sleep()单位秒。

 

解释型语言

1. 边解释,边执行。运行哪些源码,就将哪些源码转成机器码,运行多少次就重新转换多少次,所以效率低。

2. 跨平台,一次编写,到处运行。相同的源码被不同平台的解释器解释执行,生成了对应平台的机器码。所以有了解释器这个中间层,才能将源码执行在不同的平台上,跨平台的实际是解释器。

 

由上述可见,高效率的不能跨平台,跨平台的效率不高。

 

那么问题来了

1. 为什么一种语言不能在编译的时候编译成不同平台机器码的执行文件呢?

比如一次c语言开发,发布时选择windows、Linux等,生成对应平台的可执行文件。因为不同平台支持的c语言类库不同,语法也不同,要跨就得在代码层面兼容,相当麻烦。

再者像android和iOS原生开发,一个java,一个Objective-C和Swift,语言都不同,就更没法一次开发两个平台运行了。

所以根源在于不同平台的语言、cpu、操作系统等等标准不同,如果平台标准都一致,那就没那么多事了。就像秦国统一六国,确定一致的法律、货币、文字...

 

2. 为什么javascript不能由解释器直接解释成机器码保存起来运行呢?

比如不同平台的解释器一次性将源码转成机器码,保存起来运行。因为编译是个长的过程,解释型语言是马上开始执行,再者机器码相当大,一份几kb的javascript=几M的机器码。

所以对于看重启动时间的场合,比如打开浏览器看个网页就要等好几十秒的编译或者下载上百M的机器码来执行,那可等不了。 

 

 所以为了又要跨平台,又要高效率,就有了各种技术解决方案。JIT就是其中一种。

 

V8架构,V8中的JIT

例如google用c++编写javascript引擎V8,在chrome浏览器中使用。

一次编写javascript,可以在pc端,移动端等chrome浏览器中执行。

 

2008年早期V8是将javascript直接编译成机器码执行。

 

2010年发布Crankshaft编译器。因为由于编译的代码优化有限,如果函数被多次执行,则由更优的编译器Crankshaft重新编译,生成更优化的代码,从而提升性能。

 

2015年引入TurboFan编译器。因为之前代码的优化依然有限,又加入了TurboFan。

 

2016年加入Ignition解释器。由于直接将源码编译成机器码,这个架构问题是内存消耗特别大,尤其是移动设备,Full-Codegen编译的代码几乎占chrome浏览器三分之一,为代码运行留下的内存就更少了。

所以加入了Ignition解释器,引入字节码,旨在减少内存。

 

字节码是一种中间码,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。

 

2017年发布全新编译pipeline。Ignition和TurboFan的组合编译执行代码。原来的Crankshaft和Full-Codegen不再用于执行javascript。

最新架构主要是3个部分:

1 解析器Parser

2 解释器Ignition

3 优化编译器TurboFan

javascript执行过程先由解析器Parser解析为抽象语法树AST,解释器Ignition将AST翻译为字节码,一边解释一边执行。

解释器Ignition会记录代码片段运行次数,如果运行次数达到某个阈值,就将代码标记为热代码hot code,由TurboFan编译生成优化机器码。

当这段代码再次被运行时,不再解释,而是直接使用优化机器码执行,从而大大提高效率。

这种运行时代码编译技术,就叫JIT(即时编译)

 

Java跨平台,Java中的JIT

Java是一种编译与解释共存的语言。Java源码编译成字节码.class,在运行时通过虚拟机JVM解释成机器码执行。

为了提高效率,对于频繁执行的代码采用JIT即时编译技术,编译成机器码,下次执行到这段代码时不再解释,而是直接使用编译的代码,这样大大提高了效率。

因为解释和编译共存,所以说Java是半解释半编译语言。

跨语言:JVM只识别字节码,字节码是一种在源码和机器码之间的中间码,解决源码执行效率低和机器码不可移植问题。

跨平台:Java团队针对不同平台开发不同的JVM版本,将同一份Java源码可以在不同平台执行。

 

 

hybrid混合开发

hybrid混合开发,解决android和ios开发两次的问题,可以一次开发,多处运行,相当于在原生应用程序里放着可以执行js的web应用。

 

 

 

 

 

 

 

 

 

posted on 2022-05-06 03:12  gamedaybyday  阅读(359)  评论(0编辑  收藏  举报