计算机是不能理解高级语言,当然也就不能直接执行高级语言了。计算机只能直接理解机器语言,所以任何语言,都必须将其翻译成机器语言。任何编程语言编写的程序归根到底都是由底层机器的机器代码(01序列)执行的,无论是编译型语言还是解释型语言。而任何高级编程语言程序的源代码都是一个字符序列,这个字符序列到底层的01序列是通过编译器或解析器经过多次转换完成的。
编译 vs 解释
翻译的方式有两种:一种是编译,一种是解释。
两种方式翻译的时间不同。
- 编译型语言写的程序在被执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话 就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高,但也不能一概而论,部分解释型语言的解释器通过在运行时动态优化代码,甚至能够使解释型语言的性能超过编译型语言。。
一个完整的编译系统与 一个用C编写的程序hello.c的编译过程
- 解释则不同,解释性语言的程序不需要编译,省了道工序,解释性语言在运行程序的时候才翻译,比如解释性basic语言,专门有一个解释器能够直接执行basic程序,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就要翻译一次,效率比较低。
编译型与解释型两者各有利弊。
编译型由于程序执行速度快,同等条件下对系统要求较低,因此像开发操作系统、大型应用程序、数据库系统等时都采用它,像C/C++、Pascal /Object Pascal(Delphi)等都是编译语言。
一些网页脚本、服务器脚本及辅助开发接口这样的对速度要求不高、对不同系统平台间的兼容性有一定要求的程序则通常使用解释性语言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。
解释型语言每句代码只有在运行时,系统才知道这句代码是否有错(除Java那种先编译后解释性语言)。换句话说,由于编译型语言在运行前进行了编译,编译器对所有代码都进行了检查,这样就不会产生一些低级错误,例如使用了不存在的名字,或者使用了错误的名字。而JavaScript就可能会出现这些问题。
但随着硬件的升级和设计思想的变革,编译型和解释型语言越来越笼统,主要体现在一些新兴的高级语言上,而解释型语言的自身特点也使得编译器厂商愿意花费更多成本来优化解释器。
JAVA
JAVA语言是一种编译型-解释型语言,同时具备编译特性和解释特性(其所谓的编译过程只是将.java文件编程成平台无关的字节码.class文件,并不是像C一样编译成可执行的机器语言)。 作为编译型语言,JAVA程序要被统一编译成字节码文件——文件后缀是class。此种文件在java中又称为类文件。java类文件不能再计算机上直接 执行,它需要被java虚拟机翻译成本地的机器码后才能执行,而java虚拟机的翻译过程则是解释性的。java字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为java语言的解释执行,是由java虚拟机完成的。而在现实中,java开发工具JDK提供了两个很重要的命令来完成上面的编译和解释(翻译)过程。两个命令分别是javac.exe和java.exe,前者加载java类文件,并逐步对字节码文件进行编译,而另一个命令则对应了java语言的解释(javac.exe)过程。在次序上,java语言是要先进行编译的过程,接着解释执行。
字节码的设计并不专门针对任何一种特定的处理器硬件平台对应的指令代码(比如,Intel的Pentium微处理器或IBM的System/390处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。非常类似于机器指令的指令编码。因而通过Java的虚拟机就可以很容易的直接将字节码转换成对应于特定 CPU的机器码,从而得到较高的性能。这种转换的效率比其他解释性语言如Basic、Perl等要高得多,甚至在非常低档的CPU上也能顺利运行。不过 Java毕竟是解释性的语言,它解释执行的意义在于能够实现程序一经编译便可在众多不同的计算机上执行的跨平台运行。虽然这比C程序慢了许多,但在大多数应用中都是可以接受的。而且,现在Java也已经有了专门的代码生成器,可以很容易使用JIT编译技术将字节码直接转换成高性能的本机代码。值得一提的是,Java运行时系统在提供这个特性的同时仍具有平台独立性,因而“高效且跨平台”对Java来说不再矛盾。
“理解字节码以及理解Java编译器如何生成Java字节码与学习汇编知识对于C/C++程序员有一样的意义。”
当前已经有很多种Java虚拟机产品,包括了自由软件和商业软件。 如果在Java虚拟机之中执行Java字节码并不理想,则可以使用一些工具例如GNU Compiler for Java将Java代码或Java字节码编译成机器码并由硬件直接运行。 而有一些处理器可以直接运行Java字节码,这种处理器名为Java处理器。
C#
C#语言是编译型语言,但其“编译”过程比较特殊,具体说明如下:
C#程序在第一次运行的时候,会依赖其.NET Frameworker平 台,编译成IL中间码),然后由JIT compiler翻译成本地的机器码执行。从第二次在运行相同的程序,则不需要再执行以上编译和翻译过程,而是直接运行第一次翻译成的机器码。所以对于 C#来说,通常第一次运行时间会很长,但从第二次开始,程序的执行时间会快很多。
那么,C#为什么要进行两次“编译”呢?其实,微软想通过动态编译(由JIT compiler工具实现)来实现其程序运行的最优化。如果代码在运行前进行动态编译运行,那么JIT compiler可以很智能的根据你本地机器的硬件条件来进行优化,比如使用更好的register,机器指令等等,而不是像原来那样,build一份程序针对所有硬件的机器跑,没有充分利用各个机器的条件。
脚本语言
注:脚本语言一般都有相应的脚本引擎来解释执行。 他们一般需要解释器才能运行。JAVASCRIPT,ASP,PHP,PERL都是脚本语言。C/C++编译、链接后,可形成独立执行的exe文件。
JIT (JIT compiler,just-in-time compiler,即时编译器)
JIT编译器能够将MSIL编译成为各种不同的机器代码,以适应对应的系统平台,最终使得程序在目标系统中得到顺利地运行。
在Java编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把Java的字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。
JIT编译器分为:经济编译器和普通编译器。
JVM (Java Virtual Machine,Java虚拟机)
JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。
参考链接
问题
现在Java也已经有了专门的代码生成器,可以很容易使用JIT编译技术将字节码直接转换成高性能的本机代码。值得一提的是,Java运行时系统在提供这个特性的同时仍具有平台独立性,因而“高效且跨平台”对Java来说不再矛盾。
此处的JIT编译技术是像JVM一样,在不同平台上运用不同的JIT编译器将.class 翻译成相应的本机代码吗?下次还需要再翻译吗?还是以后直接可以运行了?