当前位置: 首页 > 图灵资讯 > 技术篇> JVM(JAVA虚拟机介绍)

JVM(JAVA虚拟机介绍)

来源:图灵教育
时间:2024-03-03 10:36:31

  JVM(JAVA虚拟机介绍)

  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表示从存储器中安装整数,anewaray表示新数组分配空间,iand表示两个整数的“和”,ret用于过程控制,表示从调用某种方法中返回。当长度大于8位时,操作数分为两个以上字节存储。JVM采用“JVM”big endian这种情况是通过编码来处理的,即高位bits存储在低字节中。这同 Motorola和其他RISC CPU采用的编码方法与Intel采用的编码方法一致little endian “低位bits存储在低位字节中的编码方法不同。   Java指令系统是为了实现Java语言而设计的,包括用于调用方法和监控多先程系统的指令。Java8位操作码的长度使JVM最多有256个指令,目前已使用160多个操作码。   2.2.2JVM指令系统 所有CPU都包含寄存器组,用于保存系统状态和处理器所需的信息。假如虚拟机定义了更多的寄存器,它可以在不访问栈或内存的情况下获得更多的信息,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU中的寄存器多,则在实现虚拟机时,处理器将花费大量时间用常规存储器模拟寄存器,这将降低虚拟机的效率。在这种情况下,JVM只设置了四个最常用的寄存器。它们是:   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操作系统的设计师自己决定碎片回收的方法。Java解释器和Hot在SUN公司开发 在Java环境中,碎片回收采用后台线程进行。这不仅为操作系统提供了良好的性能,而且使程序设计师摆脱了控制内存使用的风险。   2.5JVM存储区 JVM有两种存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法、字段名称和串常量。方法区用于存储Java方法的字节码。JVM规格中没有明确规定这两个存储区域的具体实现方法。这使得Java应用程序的存储布局在运行过程中必须确定,这取决于特定平台的实现。

  JVM是Java字节码定义的一种独立于特定平台的规格描述,是Java平台独立性的基础。目前JVM还存在一些限制和不足,需要进一步完善,但无论如何,JVM的思想是成功的。

  对比分析:如果将Java原程序想象为我们的C++原程序,Java原程序编译后生成的字节码相当于C++原程序编译后的80x86机器代码(二进制程序文件),Java解释器相当于80x86CPU。机器代码运行在80x86CPU上,Java字节码运行在Java解释器上。

  Java解释器相当于操作Java字节码”CPU”,但该“CPU它不是通过硬件实现的,而是通过软件实现的。Java解释器实际上是特定平台下的应用程序。Java字节码只要在特定平台下实现解释器程序,就可以通过解释器程序在平台下运行,这是Java跨平台的基础。目前,并非所有平台下都有相应的Java解释器程序,这也是Java无法在所有平台下运行的原因。它只能在实现Java解释器程序的平台下运行。