编译型语言与解释型语言详解_Java什么是编译与解释共存的语言

编译型语言

简述:

"一次编译,无限运行"

编译型语言在运行前,需要通过编译器将整体源码翻译为机器码(二进制指令码),进而生成可执行文件。可执行文件的运行无需源码与编译器,也就是说编译型语言可以脱离开发环境运行

跨平台性:编译型语言的跨平台性差

1.操作系统API层面(Application Programming Interface 应用程序接口)

API本身是抽象的,仅定义接口,程序通过接口调用程序,调用者无须考虑被调用者的底层实现

不同的系统提供的API实现不同,无法通过编译(若源码调用了Linux系统的API,那必然在Windows系统下无法编译通过)

2.操作系统ABI层面(Application Binary Interface 应用程序二进制接口)

ABI包括:

  • 数据类型的大小、布局与对齐;
  • 调用约定(如何传递函数的参数与如何接收函数返回值):函数参数都通过栈传递或部分函数参数通过寄存器传递、函数参数对应的寄存器等
  • 系统调用编码(system call numbers):系统调用在实现上通常以软中断(software interrupt)的方式进行,Linux使用0x80号中断作为系统调用接口,Windows使用0x2E号中断作作为系统调用接口);
  • 程序如何向操作系统进行系统调用:直接调用或通过procedure calls间接调用;
  • 可执行文件的二进制格式(Linux为ELF,Windows为PE)
  • 二进制程序库;
  • ......

不同系统下编译生成的机器码不同(受调用约定等因素的影响),无法得到正确的结果

不同系统下编译生成的生成的可执行文件格式不同(受可执行文件的二进制格式影响),无法运行可执行文件

综上所述,编译型语言的跨平台性主要体现在:

  • 不同操作系统的API实现不同,无法编译通过
  • 不同操作系统下编译生成的机器码不同,无法得到正确的结果
  • 不同操作系统下编译生成的可执行文件格式不同,无法运行可执行文件

附:Windows系统与类Unix系统的数据类型占用字节数表:

操作系统(64位) short int long float double
Windows 2 4 4 4 8
类Unix(Unix、Linux、MacOS等) 2 4 8 4 8

注:Windows平台中,C语言的long类型为4字节,Java的long类型为8字节 

解释型语言

简述:

"一次编写,到处运行"

解释型语言可直接运行源码,在运行源码时,解释器逐行将源码翻译为机器码,但不生成可执行文件,也就是说再次运行源码时需要再次进行解释,所以解释型语言无法脱离开发环境运行,而且运行效率低于编译型语言,甚至存在数量级的差距

跨平台性:解释型语言的跨平台性好

需要注意的是,源码跨平台,但解释器不跨平台

上文中提到,可执行文件无法跨平台,而解释器就是一个将源码翻译为机器码的可执行文件,所以针对不同的平台有不同的解释器,以此屏蔽不同平台间的差异;换句话说,只要平台安装了对应的解释器,就可以直接运行源码,不同的平台上运行同一段源码,得到的结果是相同的

Java属于编译与解释并存的语言

Java的运行过程:Java源码文件(.java)经 javac编译器 编译生成字节码文件(.class),字节码文件交由JVM处理

JVM的处理方式为:

1.运行时,JVM将字节码逐行转交给解释器,解释器将字节码翻译为机器码

2.运行时,部分字节码可能由JIT(Just In Time Compiler 实时编译器)编译器编译为机器码并存入缓存,再次运行时可直接调用,无需解释(存在纯JIT编译、无解释器的JVM,例如:JRockit、Maxine VM);通常而言,被JIT编译的字节码属于"热点代码",例如循环体代码,毕竟对"热点代码"进行编译并缓存可以达到事半功倍的效果

HotSpot VM内的JIT编译器分为 Client Compiler 与 Server Complier ,简称为C1编译器与C2编译器;VM对其使用分层策略(Tiered Compilation),策略令C1与C2同时工作,部分代码可能多次编译;通常而言,利用C1实现快速编译,利用C2实现深度优化编译

分层策略:

  • 0层:解释运行,解释器不开启性能监视(Profiling);可触发1层
  • 1层:利用C1编译器将字节码编译为机器码,其间进行简单但可靠的优化,必要时将加入性能监控;可触发2层
  • 2层:利用C2编译器将字节码编译为机器码,但会进行深度优化,甚至可能根据性能监控进行不可靠的激进优化(激进优化出现问题时,会将字节码交付给解释器,无解释器的JVM则会将字节码交付给C1编译器)

此外:

JVM还存在AOT(Ahead Of Time Compiler 预编译器)编译,即通过AOT编译器将源码直接编译为静态机器码,跳过了 javac编译器 ,也跳过了解释器,令Java代码的第一次运行速度显著提升(不计算预编译耗时的话)

AOT方式存在一定的缺陷:

  • 代码质量:预编译生成静态机器码时,无法根据硬件情况或代码运行情况择优选择机器码序列,性能通常而言不如JIT
  • 无动态性:无法使用反射机制,无法动态加载类(只有编译时类型,无运行时类型)等(运行的是机器码,而不是源码)
  • 牺牲平台无关性(参考编译型语言)

注:解释器、JIT编译器、AOT编译器可以一起工作

语言的"编译型"与"解释型"并不是绝对的

其实,通常我们都说C语言是编译型语言,但其实C语言的解释器也是存在的,例如Ch,所以C语言所谓的"编译型语言",只是指其主流实现方式为编译,并不代表其不能进行解释;相对的,Python等"解释型语言",也并不是无法编译

不可跨平台,平台指CPU而非操作系统时

通常来说编译器的默认指令集是十分保守的,以确保最大限度地可被CPU识别,但开发者可设置编译器在编译时使用新指令集,此时不支持新指令集的旧CPU就会无法识别机器码,从而无法运行可执行文件

你可能感兴趣的:(Java,java)