快捷搜索:

JAVA文件编译执行与虚拟机(JVM)介绍

Java虚拟机(JVM)是可运行Java代码的假想谋略机。只要根据JVM规格描述将说冥器移植到特定的谋略机上,就能包管颠末编译的任何Java代码能够在该系统上运行。本文首先简要先容从Java文件的编译到终极履行的历程,随后对JVM规格描述作一阐明。

一.Java源文件的编译、下载、解释和履行

Java利用法度榜样的开拓周期包括编译、下载、解释和履行几个部分。Java编译法度榜样将Java源法度榜样翻译为JVM可履行代码?字节码。这一编译历程同C/C++的编译有些不合。当C编译器编译天生一个工具的代码时,该代码是为在某一特定硬件平台运行而孕育发生的。是以,在编译历程中,编译法度榜样经由过程查表将所有对符号的引用转换为特定的内存偏移量,以包管法度榜样运行。Java编译器却不将对变量和措施的引用编译为数值引用,也不确定法度榜样履行历程中的内存结构,而是将这些符号引用信息保留在字节码中,由说冥器在运行历程中创立内存结构,然后再经由过程查表来确定一个措施所在的地址。这样就有效的包管了Java的可移植性和安然性。

运行JVM字节码的事情是由说冥器来完成的。解释履行历程分三部进行:代码的装入、代码的校验和代码的履行。装入代码的事情由"类装载器"(class loader)完成。类装载器认真装入运行一个法度榜样必要的所有代码,这也包括法度榜样代码中的类所承袭的类和被其调用的类。当类装载器装入一个类时,该类被放在自己的名字空间中。除了经由过程符号引用自己名字空间以外的类,类之间没有其他法子可以影响其他类。在本台谋略机上的所有类都在同一地址空间内,而所有从外部引进的类,都有一个自己自力的名字空间。这使得本地类经由过程共享相同的名字空间得到较高的运行效率,同时又包管它们与从外部引进的类不会互相影响。当装入了运行法度榜样必要的所有类后,说冥器便可确定全部可履行法度榜样的内存结构。说冥器为符号引用同特定的地址空间建立对应关系及查询表。经由过程在这一阶段确定代码的内存结构,Java很好地办理了由超类改变而使子类崩溃的问题,同时也防止了代码对地址的不法造访。

随后,被装入的代码由字节码校验器进行反省。校验器可发明操作数栈溢出,不法数据类型转化等多种差错。经由过程校验后,代码便开始履行了。

Java字节码的履行有两种要领:

1.即时编译要领:说冥器先将字节码编译成机械码,然后再履行该机械码。

2.解释履行要领:说冥器经由过程每次解释并履行一小段代码来完成Java字节码程 序的所有操作。

平日采纳的是第二种措施。因为JVM规格描述具有足够的机动性,这使得将字节码翻译为机械代码的事情

具有较高的效率。对付那些对运行速率要求较高的利用法度榜样,说冥器可将Java字节码即时编译为机械码,从而很好地包管了Java代码的可移植性和高机能。

二.JVM规格描述

JVM的设计目标是供给一个基于抽象规格描述的谋略机模型,为解释法度榜样开拓职员提很好的机动性,同时也确保Java代码可在相符该规范的任何系统上运行。JVM对着实现的某些方面给出了详细的定义,分外是对Java可履行代码,即字节码(Bytecode)的款式给出了明确的规格。这一规格包括操作码和操作数的语法和数值、标识符的数值表示要领、以及Java类文件中的Java工具、常量缓冲池在JVM的存储映象。这些定义为JVM说冥器开拓职员供给了所需的信息和开拓情况。Java的设计者盼望给开拓职员认为所欲为应用Java的自由。

JVM定义了节制Java代码解释履行和详细实现的五种规格,它们是:

JVM指令系统

JVM寄存器

JVM栈布局

JVM碎片收受接收堆

JVM存储区

2.1JVM指令系统

JVM指令系统同其他谋略机的指令系统极其相似。Java指令也是由 操作码和操作数两部分组成。操作码为8位二进制数,操作数进紧随在操作码的后面,其长度根据必要而不合。操作码用于指定一条指令操作的性子(在这里我们采纳汇编符号的形式进行阐明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的"与",ret用于流程节制,表示从对某一措施的调用中返回。当长度大年夜于8位时,操作数被分为两个以上字节寄放。JVM采纳了"big endian"的编码要领来处置惩罚这种环境,即高位bits寄放在低字节中。这同 Motorola及其他的RISC CPU采纳的编码要领是同等的,而与Intel采纳的"little endian "的编码要领即低位bits寄放在低位字节的措施不合。

Java指令系统因此Java说话的实现为目的设计的,此中包孕了用于调用措施和监视多先程系统的指令。Java的8位操作码的长度使得JVM最多有256种指令,今朝已应用了160多种操作码。

2.2JVM指令系统

所有的CPU均包孕用于保存系统状态和处置惩罚器所需信息的寄存器组。假如虚拟机定义较多的寄存器,便可以从中获得更多的信息而不必对栈或内存进行造访,这有利于前进运行速率。然而,假如虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用场置惩罚器大年夜量的光阴来用老例存储器模拟寄存器,这反而会低落虚拟机的效率。针对这种环境,JVM只设置了4个最为常用的寄存器。它们是:

pc法度榜样计数器

optop操作数栈顶指针

frame当前履行情况指针

vars指向当前履行情况中第一个局部变量的指针

所有寄存器均为32位。pc用于记录法度榜样的履行。optop,frame和vars用于记录指向Java栈区的指针。

2.3JVM栈布局

作为基于栈布局的谋略机,Java栈是JVM存储信息的主要措施。当JVM获得一个Java字节码利用法度榜样后,便为该代码中一个类的每一个措施创建一个栈框架,以保存该措施的状态信息。每个栈框架包括以下三类信息:

局部变量

履行情况

操作数栈

局部变量用于存储一个类的措施中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。

履行情况用于保存说冥器对Java字节码进行解释历程中所需的信息。它们是:上次调用的措施、局部变量指针和操作数栈的栈顶和栈底指针。履行情况是一个履行一个措施的节制中间。例如:假如说冥器要履行iadd(整数加法),首先要从frame寄存器中找到当前履行情况,而后便从履行情况中找到操作数栈,从栈顶弹出两个整数进行加法运算,着末将结果压入栈顶。

操作数栈用于存储运算所需操作数及运算的结果。

2.4JVM碎片收受接收堆

Java类的实例所需的存储空间是在堆上分配的。说冥器详细承担为类实例分配空间的事情。说冥器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的应用。一旦工具应用完毕,便将其收受接收到堆中。

在Java说话中,除了new语句外没有其他措施为一工具申请和开释内存。对内存进行开释和收受接收的事情是由Java运行系统承担的。这容许Java运行系统的设计者自己抉择碎片收受接收的措施。在SUN公司开拓的Java说冥器和Hot Java情况中,碎片收受接收用后台线程的要领来履行。这不只为运行系统供给了优越的机能,而且使法度榜样设计职员开脱了自己节制内存应用的风险。

2.5JVM存储区

JVM有两类存储区:常量缓冲池和措施区。常量缓冲池用于存储类名称、措施和字段名称以及串常量。措施区则用于存储Java措施的字节码。对付这两种存储区域详细实现要领在JVM规格中没有明确规定。这使得Java利用法度榜样的存储结构必须在运行历程中确定,依附于详细平台的实现要领。

JVM是为Java字节码定义的一种自力于详细平台的规格描述,是Java平台自力性的根基。今朝的JVM还存在一些限定和不够,有待于进一步的完善,但无论若何,JVM的思惟是成功的。

比较阐发:假如把Java原法度榜样想象成我们的C++原法度榜样,Java原法度榜样编译后天生的字节码就相称于C++原法度榜样编译后的80x86的机械码(二进制法度榜样文件),JVM虚拟机相称于80x86谋略机系统,Java说冥器相称于80x86CPU。在80x86CPU上运行的是机械码,在Java说冥器上运行的是Java字节码。

Java说冥器相称于运行Java字节码的“CPU”,但该“CPU”不是经由过程硬件实现的,而是用软件实现的。Java说冥器实际上便是特定的平台下的一个利用法度榜样。只要实现了特定平台下的说冥器法度榜样,Java字节码就能经由过程说冥器法度榜样在该平台下运行,这是Java跨平台的根本。当前,并不是在所有的平台下都有响应Java说冥器法度榜样,这也是Java并不能在所有的平台下都能运行的缘故原由,它只能在已实现了Java说冥器法度榜样的平台下运行。

您可能还会对下面的文章感兴趣: