Java虚拟机的设计和实现_第1页
Java虚拟机的设计和实现_第2页
Java虚拟机的设计和实现_第3页
免费预览已结束,剩余45页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java虚拟机的设计和实现第一章绪论6Java及Java虚拟机6.Java虚拟机的体系结构7.MiniJavaVM的功能10MiniJavaVM的运行环境及开发工具2系统设计132.1 唯一的虚拟机MiniJavaVM13MiniJavaVM的构成要素1.3虚拟机总体框架13命令参数解析模块15类的装载和解析模块1522J内存管理模块16执行引擎模块17方法调用模块18异常处理模块19第三章虚拟机框架的实现213.1 JVM工程223.2.1 JavaVM工程23Java虚拟机的数据类型和字长考量23JavaVM类24JavaNativeCall工程29第四章类的装载和解析304.1 Java

2、Class文件304.2 Class文件在MiniJavaVM中的数据结构表示32类的装载和IS析36第五章内存管理415.1 对象、堆、方法区的管理41MiniJavaVM44第六章执行引擎一一Java操作码实现476.1 Java虚拟机中的操作码功能分类47操作码功能实现JavaOperatorExecute类49第七章方法调用的实现507.1 Java中的方法调用507.2 非本地方法的实现5.17J本地方法的实现52Java中的本地方法52NativeMethod_access类54如何处理本地,方法可如参数问木54第八章异常的实现568.1 Java中的异常5682异常在MiniJa

3、vaVM中的实现56第九章验证MiniJavaVM的正确性589.1 MiniJavaVM的使用方法589.2.1 测试操作码实现的正确性.6.1方法调用的正确性61数学运算的正确性64控制流语句的正确性659.2 测试本地方法调用66测试异常处理67第十章不足与后续工作6910.1 本地方法6910.2 I/O操作6910.3 多线程.69效率69致谢71参考文献72摘要本文叙述了Java虚拟机(JVM)的概念及如何设计和实现一个Java虚拟机MiniJavaVM。着重介绍了虚拟机的体系结构及如何设计和实现这个体系结构。在探讨虚拟机的设计过程中详细介绍了MiniJavaVM虚拟机各部分的设计

4、,包括类的装载和解析,内存管理,执行引擎,方法调用和异常处理部分。最后通过测试MiniJavaVM来验证设计和实现的正确性。关键词Java虚拟机(JVM)字节码类装载执行引擎本地方法MiniJavaVM-adesignandimplementationofaJavaVirtualMachineAbstractThispaperdescribestheconceptionofJavaVirtualMachine(JVM)andhowtodesignandimplementaJavaVirtualMachine-MiniJavaVM.ItemphasizesthearchitectureofJVM

5、andhowtodesignandimplementthearchitecture.ItdescribesthedetailsabouteachpartofJVMwhendiscussinghowtodesigntheJVM,includingclass-loadingandresolution,memorymanagement,executionengine,methodinvokingandexception-handling.Atlast,thecorrectnessofthedesignandimplementationisvalidatedbytestingMiniJavaVM.Ke

6、ywordsJavaVirtualMachine(JVM),bytecode,Class-loading,executionengine,NativeMethod.第一章绪论1.1 Java及Java虚拟机说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(JavaAPI)。它们的关系如下图所示:1J号虚拟机图1.1.1Java四个方面的关系运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件)。最后字节码被装入内存

7、,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。从上图也可以看出Java平台由Java虚拟机和Java应用程序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平台上。这个平台的结构如下图所示:1应用程序和小应用程序“饵基本API怕标准扩展APIJava标准扩展美Java虚拟机稼棺会口适配器适配器适配器Java噪作汞貌倒览器系统麋作系貌硬件一硬件硬件浏1览器上的用能桌面操作系藐上的Java小型操作系统上的JavaJava操作系舞的Java图1.1.2Javsff台结构在Java平台的结构中,可以看出,Jav

8、a虚拟机(JVM)处在核心的位置,是程序与底层操作系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统,其中依赖于平台的部分称为适配器;JVM通过移植接口在具体的平台和操作系统上实现;在JVM的上方是Java的基本类库和扩展类库以及它们的API,利用JavaAPI编写的应用程序(application)和小程序(Javaapplet)可以在任何Java平台上运行而无需考虑底层平台,就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java的平台无关性。1什么是Java虚拟机?Java虚拟机是运行所有Java程序的抽象计算机,它仅仅是由一

9、个规范来定义的抽象的计算机。当提及“Java虚拟机”时,可能指的是如下三种不同的东西:抽象规范一个具体的实现一个运行中的虚拟机实例2Java虚拟机负责Java程序设计语言的内存安全、平台无关和安全特性。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机(JVM)在多个平台上实现统一语言。Java之所以得以大行其道,除了它是一门面向对象、构造精美的语言之外,更重要的原因在于:它摆脱了具体机器的束缚,使跨越不同平台编写程序成为可能。1.2 Java虚拟机的体系结构在Java虚

10、拟机规范中,一个虚拟机实例的行为是分别按照子系统、内存区、数据类型以及指令这几个术语来描述的。这些组成部分一起展示了抽象的虚拟机的内部抽象体系结构。但是规范中对它们的定义并非是要强制规定Java虚拟机实现内部的体系结构,更多的是为了严格地定义这些实现的内部特征。规范本身通过定义这些抽象的组成部分以及它们之间的交互,来定义任何Java虚拟机实现都必须遵守的行为。每个JVM都有两种机制,一个是装载具有合适名称的类(类或是接口),叫做类装载子系统;另外的一个负责执行包含在已装载的类或接口中的指令,叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈这五个部分,这几个部分和类装

11、载机制与运行引擎机制一起组成了Java虚拟机的体系结构。图1.2.1描述了Java虚拟机的结构框图,包括在规范中描述的主要子系统和内存区。Class文件本地方法接口本地方法库图1.2.1Javs拟机的内部体系结构每个Java虚拟机都有一个类装载器子系统,它根据给定的全限定名来装入类型(类或接口)。同样,每个Java虚拟机都有一个执行引擎,它负责执行那些包含在被装载类的方法中的指令。Java虚拟机的运行时数据区存储了许多运行时数据,例如,字节码,从已装载的class文件中得到的其他信息,程序创建的对象,传递给方法的参数,返回值,局部变量,以及运算的中间结果等。Java虚拟机把这些东西都组织到几个

12、“运行时数据区”中,以便于管理。某些运行时数据区是由程序中所有线程共享的,还有一些则只能由一个线程拥有。每个Java虚拟机实例都有一个方法区及一个堆,它们是由该虚拟机实例中所有线程共享的。当虚拟机装载一个class文件时,它会从这个class文件包含的二进制数据中解析类型信息。然后把这些类型信息放到方法区中。当程序运行时,虚拟机会把所有该程序在运行时创建的对象都放到堆中。图1.2.2描述了这些内存区域。I对象(对象图1.2.2由所有线程共享的运行时数据区当每一个线程被创建时,它都将得到它自己的PC寄存器以及一个Java栈。如果线程正在执行的是一个Java方法(非本地方法),那么PC寄存器的值将

13、总是指示下一条将被执行的指令,而它的Java栈则总是存储该线程中Java方法调用的状态一一包括它的局部变量,被调用时传进来的参数,它的返回值,以及运算的中间结果等。而本地方法调用的状态,则是以某种依赖于具体实现的方式存储在本地方法栈中,也可能是在寄存器或其他某些与特定实现相关的内存区中。Java栈是由许多栈帧(stackframe)组成的,一个栈帧包含一个Java方法调用的状态。当线程调用一个Java方法时,虚拟机压入一个新的栈帧到该线程的Java栈中;当该方法返回时,这个栈帧被从Java栈中弹出并抛弃。Java虚拟机没有寄存器,其指令集使用Java栈来存储中间数据。这样设计的原因是为了保持J

14、ava虚拟机的指令集尽量紧凑,同时也便于Java虚拟机在那些只有很少通用寄存器的平台上实现。另外,Java虚拟机的这种基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。图1.2.3描绘了Java虚拟机为每个线程创建的内存区,这些内存区是私有的,任何线程都不能访问另一个线程的PC寄存器或者Java栈。3线程3PC寄存器1.3MiniJavaVM线程1栈帧栈帧栈帧栈帧线程2栈帧栈帧栈帧Jav哦线程3线程3栈帧栈帧本地方法栈图1.2.3线程专有的运行时数据区的功能能够装载并解析javaclass文件对于已经编译好的javaclass文件,能够读取该class文件的内容

15、,装载该类,并保存在程序内部的数据结构中。当在程序运行的过程中需要解析该类时,进行解析,并替换符号引用为直接引用在完成虚拟机的初始化后,能够找到main函数并执行程序错误!未定义书签。main()方法,如果找到,对于指定的入口类,在虚拟机完成了初始化后,寻找该类的则执行该方法,否则抛出异常,虚拟机运行中止。支持Java虚拟机规范中规定的200多个操作码的功能实现了Java虚拟机的200多个操作码的功能,由此使MiniJavaVM这个虚拟机模拟Java虚拟机的功能成为可能,这200多个操作码包括:栈和局部变量操作指令?将常量池入指令?从栈中的局部变量中装载值指令?将栈中的值存入局部变量指令?通用

16、栈操作指令类型转换指令整数运算指令逻辑运算指令?移位操作指令按位布尔运算指令浮点运算指令?对象和数组指令?对象操作指令?数组操作指令?控制流指令?条件分支指令?比较指令?无条件转移指令?表跳转指令?异常指令?finally子句指令?方法调用与返回指令?方法调用指令?方法返回指令?线程同步指令具有内存管理和垃圾收集机制Java虚拟机对内存的管理使得java程序具有很高的安全性,程序员不用担心内存访问越界问题,也不用为在合适的时候释放分配的空间而费心。垃圾收集机制的存在解决何时回收不用的内存和如何回收内存的问题。支持非本地方法调用按照Java虚拟机规范中的要求来设置非本地方法的调用情况,包括参数压

17、栈,分配局部变量空间,压入方法调用的栈桢等。支持本地方法调用Java虚拟机中所有与本地方法相关的部分都重新写过,以动态链接库的形式为MiniJavaVM工程提供支持。MiniJavaVM的本地方法只实现最基本的功能,不再负责虚拟机的安全机制。支持异常处理有了异常处理,就能够在程序运行时平稳处理意外情况。根据Javaclass文件中的异常表,MiniJavaVM程序支持所有的异常处理,并在不能解决异常时输出异常信息,虚拟机停止运行。能够运行与I/O无关的完整Java程序,并提供参数供查看运行效果提供了-version,-showversion,-help,-?,-verbose命令。-versi

18、on命令显示MiniJavaVM的版本信息,然后退出-showversion命令显示MiniJavaVM的版本信息,然后继续运行Java程序-help,-?命令显示帮助信息1.4 -verbose命令输出详细数据显示运行过程MiniJavaVM的运行环境及开发工具开发平台:WindowsXP/2003开发语言:ANSIC/C+开发工具:VisualStudioC+/VisualS运行平台:WindowsXP/2000/2003第二章系统设计2.1 唯一的虚拟机MiniJavaVM一个运行的Java虚拟机实例的夭职就是:负责运行一个Java程序。当启动一个Java程序时,一个虚拟机实例也就诞生了

19、。当该程序关闭退出,这个虚拟机实例也就随之消亡。如果在同一台计算机上同时运行三个Java程序,将得到三个Java虚拟机实例。每个Java程序实例都运行于它自己的Java虚拟机实例中。错误!未定义书签。为此,需要有一种机制保证在运行过程中只有一个Java虚拟机的实例产生。首先要定义表示Java虚拟机的类,然后保证这个类有只一个实例。一种可以供选择的方案是使用Singleton设计模式,保证Java虚拟机实例在整个程序运行过程中只有一个;另一种是可以考虑MFC(MicrosoftFundamentalClass)中唯一的全局变量theApp来表示程序运行的实例,通过AfxGetApp()的方法来得

20、到该唯一的全局变量的指针,然后在此基础上进行操作。在这里,我们选择MF5式定义唯一的全局变量来表示Java虚拟机的运行实例,可以在程序进入main()函数前完成虚拟机的初始化。通过定义一个全局函数来返回虚拟机实例的指针。2.2 MiniJavaVM的构成要素2.2.1 虚拟机总体框架我们的MiniJavaVM的框架合理地组织了虚拟机运行时所需的各模块,将各模块的输入与输出有效地结合在一起,使这些模块组合在一起完成了Java虚拟机的功能。这些模块包括:命令参数解析模块、类的装载和解析模块、内存管理模块、执行引擎模块、方法调用模块、异常处理模块、多线程处理模块(未完成)。我们的MiniJavaVM

21、总的组织方式如图2.2.1所示。输入命令:命令参数解析模块U:根据MiniJavaVM后的参数来设定虚拟机:的运行模式及输出信息1类的装载和解析模块:内存管理模块:装载指定名称的java类,并采用退解析;的方式在需要时解析该类,类的信息维:护在虚拟机的一个数据结构中为类的实例及静态字段分配空间并在虚拟机内维护实例,当空间不足时启动垃圾回收机制来回收内存当调用一个方法时(本地方法与非本地方法)使用此模块,包括找到指定方法全限定名的方法与处理参数压栈及调用方法并返回的过程:当虚拟机抛出异常且不能处理时;记录异常信息,在程序退出前输出虚拟机图2.2.1MiniJavaVM的模块组织其中除命令参数解析

22、模块外,其他模块一起构成了完整的MiniJavaVM虚拟机,这些模块之间协同合作,完成了虚拟机的功能。其中命令参数解析模块负责解析命令,根据MiniJavaVM后的参数来设定虚拟机的运行模式及输出信息;类的装载和解析模块能从class文件或是rt.jar文件中装载指定名称的Java类,并采用退解析的方式在需要时解析该类,类的信息维护在虚拟机的一个数据结构中;内存管理模块负责为类的实例及静态字段分配空间,并在虚拟机内维护类的实例和静态字段,当虚拟机空间不足时会启动垃圾回收机制来回收内存;执行引擎模块负责解释执行200多个操作码,解释的过程包括对栈桢、栈、PG局部变量区的修改;多线程处理模块负责维

23、护虚拟机内的表示线程的数据结构,在语言级提供多线程支持;方法调用模块负责处理方法调用过程,对于非本地方法,包括找到调用方法的指针,新建栈桢、将方法参数设置在新栈桢的局部变量区,调用方法并将返回值压栈的过程,对于本地方法,包括找到调用方法的指针,将方法参数用汇编的方式压栈,调用本地方法并将返回值压栈的过程;异常处理模块负责处理虚拟机抛出的异常,记录异常产生处的异常信息,并试图通过查找当前方法的异常表来处理异常信息,如果能够通过异常表找到处理异常的代码,则修改PC的值使虚拟机处理当前异常,否则,当虚拟机不能处理该异常时,输出MiniJavaVM虚拟异常信息,然后终止虚拟机的运行。通过这几个模块的协

24、同合作,我们的机能够很好地模拟Java虚拟机的功能。2.2.2命令参数解析模块命令参数解析模块负责解析命令行,根据MiniJavaVM后的参数来设定虚拟机的运行模式及输出信息。该模块的设计如图2.2.2所示:命令参数解析模块4命令行参数将命令行参数翻译成虚拟机运行时参数图2.2.2命令行参数解析模块命令参数解析模块在解析完命令行参数后,通过得到虚拟机的唯一实例的指针调用设置参数的方法来设置虚拟机运行时的参数。2.2.3类的装载和解析模块类的装载和解析模块负责从javaclass类,并采用退解析的方式在需要时解析该类,文件或是rt.jar文件中装载指定名称的Java类的信息维护在虚拟机的一个数据

25、结构中。我们的MiniJavaVM类的装载和解析模块设计如图2.2.3所示:需要解析类信息1类的装载和解析模块I:类的装载和解析过程I图2.2.3类的装载和解析模块其中要装载的类文件有两种渠道获得,一种是直接查找相应类的class文件,一种是从rt.jar文件中得到类的class文件的数据,为了统一这两种方式,可以先从这两种方法中生成类文件的字节流,再交由下一步程序处理。当生成class文件的字节流后,通过指定的模块读取字节流中的信息,生成该Java类在虚拟机中对应的数据。这样,类装载的部分算是完成。在虚拟机运行的过程中,会需要解析类中的常量池,将符号引用替换为直接引用。2.2.4内存管理模块

26、内存管理模块负责为类的实例及静态字段分配空间,并在虚拟机内维护类的实例和静态字段,当虚拟机空间不足时会启动垃圾回收机制来回收内存。在Java虚拟机中,关于被装载类型的信息存储在一个逻辑上称为方法区的内存中,所有线程共享方法区,因此它们对方法区数据的访问必须被设计为是线程安全的。方法区的大小不必是固定的,虚拟机可以根据应用的需要动态调整。同样,方法区也不必是连续的,方法区可以在一个堆(甚至是虚拟机自己的堆)中自由分配。另外,虚拟机也可以允许用户或者程序员指定方法区的初始大小以及最小和最大尺寸等。错误!未定义书签。方法区也可以被垃圾收集。因为虚拟机允许用户定义的类装载器来动态扩展Java程序,因此

27、一些类也会成为程序不再引用”的类。当某个类变为不再被引用的类时,Java虚拟机可以卸载这个类(垃圾收集),从而使方法区占据的内存保持最小。为了简单,我们的MiniJavaVM的方法区使用虚拟机自己的堆,不参与垃圾回收,同时,类的静态字段及一些特殊的类的实例(如与每个类相关的Class类的实例)也不参与垃圾回收。我们的MiniJavaVM内存管理模块设计如图2.2.4所示::内存管理模块当MiniJavaVM虚拟机请求一个可以被回收的内存空间(比如普通类的实例空间)时,则通过内存管理模块分配可回收的内存,所分配的内存的实地址经过映射后返回给虚拟机,同时已分配的内存地址记录在一张哈希表中,供快速查

28、找所用。如果虚拟机已经没有可分配的空间,则运行垃圾收集,垃圾收集完成后再分配内存。当虚拟机请求一个不可被回收的内存空间(比如类的静态字段空间,表示已装载类的Class类的实例等)时,通过内存管理模块分配不可回收内存,所分配的内存的实地址经过映射后返回给虚拟机,同时已分配的内存地址记录在一张哈希表中,供快速查找所用。当垃圾收集完成后仍没有可分配的内存地址可用时,虚拟机退出。2.2.5执行引擎模块任何Java虚拟机实现的核心都是它的执行引擎。在Java虚拟机规范中,执行引擎的行为使用指令集来定义。对于每条指令,Java虚拟机规范都详细规定了当实现执行到该指令时应该处理什么。错误!未定义书签。执行引

29、擎模块负责解释执行Java200多个操作码,解释的过程包括对Java栈桢、Java栈、PG局部变量区的修改。我们的MiniJavaVM执行引擎模块设计如图2.2.5所示::执行引擎模块字节码流解释完成操作码的功能取操无操作码判断是否是Java操作码结束虚拟机运行异常图2.2.5执行引擎模块在调用执行引擎模块时,会传入一字节码流,执行引擎模块负责解释这一字节码流。在解释字节码过程中,Java虚拟机可能会装载新的Java类,分配某个Java类的实例,进行数学运算,修改当前java栈桢、Java栈、PG局部变量区等。2.2.6方法调用模块方法调用模块负责处理方法调用过程,对于非本地方法,包括找到调用

30、方法的指针,新建栈桢、将方法参数设置在新栈桢的局部变量区,调用方法并将返回值压栈的过程,对于本地方法,包括找到调用方法的指针,将方法参数用汇编的方式压栈,调用本地方法并将返回值压栈的过程。我们的MiniJavaVM方法调用模块的设计如图2.2.6所示:如有异常抛出异常,调用异常处理模块1方法调用模块非本地方法查找该方法在虚拟机中对应的数据结构I本地方法Java方法调用调用方法的名称和描述符图2.2.6方法调用模块虚拟机为每一个调用的Java(非本地)方法一个新的栈帧。栈帧包括:为方法的局部变量所预留的空间,该方法的操作数栈,以及特定虚拟机实现需要的其他所有信息。局部变量和操作数栈的大小在编译时

31、计算出来,并放置到class文件中去,然后虚拟机就能够了解到方法的栈帧需要多少内存。当虚拟机调用一个方法的时候,它为该方法创建恰当大小的栈帧,再将新的栈帧压入Java栈。处理实例方法时,虚拟机从所调用方法栈帧内的操作数栈中弹出objectref和args。虚拟机把objectref作为全局变量0放到新的栈帧中,把所有的args作为局部变量1,2,等处理。Objectref是隐式传给所有实例方法的this指针。对于类方法,虚拟机只从所调用的方法栈帧中的操作数栈中弹出参数,并将它们放到新的栈帧中去作为局部变量0,1,2当objectref和args(对于类方法则只有args)被赋给新栈帧中的局部变

32、量后,虚拟机把新的栈帧作为当前栈帧,然后将程序计数器指向新方法的第一条指令。错误!未定义书签。虚拟机使用一种与实现相关”的风格调用本地方法。当调用本地方法时,虚拟机不会将一个新的栈帧压入Java栈。当线程进入到本地方法的那一刻,它就将Java栈抛在身后。直到本地方法返回以后,Java栈才被重新调用。这里本虚拟机的实现将使用调用动态链接库中的方法来实现本地方法调用的过程。2.2.7 异常处理模块异常处理模块负责处理虚拟机抛出的异常,记录异常产生处的异常信息,并试图通过查找当前方法的异常表来处理异常信息,如果能够通过异常表找到处理异常的代码,则修改PC的值使虚拟机处理当前异常,否则,当虚拟机不能处

33、理该异常时,输出异常信息,然后终止虚拟机的运行。我们的MiniJavaVM异常处理模块的设计如图2.2.7所示:异常处理模块图2.2.7异常处理模块第三章虚拟机框架的实现Java虚拟机的体系结构如图3.1所示:Class文件类装载器子系统方法区堆JavaBPC寄存器本地方法栈运行时数据区本地方法接口本地方法库图3.1Java虚拟机的内部体系结构实现虚拟机框架,需要考虑以下几点:虚拟机的数据类型和字长如何实现栈结构如何装载和解析类如何调用本地和非本地方法如何实现执行引擎如何实现多线程机如何组织方法区和堆如何进行垃圾回收虚拟机如何处理异常为了解决这些问题,这里我们把MiniJavaVM虚拟机的实现

34、总体分为三部分。第一部分为主体部分,JavaVM工程。这个工程相当于实现了一个Java虚拟机的所有功能,包括定义虚拟机的数据类型和字长,实现虚拟机栈结构,组织方法区和堆,装载和解析类,实现执行引擎,调用非本地方法,实现多线程,处理异常等。但这个工程不负责虚拟机在执行过程中需要调用的本地方法的实现。由于本地方法总是与Java虚拟机实现的底层平台相关的,因此这个工程只负责处理与底层平台实现不相关的部分,而将与底层平台实现相关的部分交给另外一个工程JavaNativeCall工程。JavaVM工程将开发为动态链接库的形式,有利于别的工程调用这个工程中重要的导出类和导出方法。第二部分为本地方法实现部分

35、,JavaNativeCall工程。此工程负责本地方法接口(JNI)的声明和实现。该工程将开发为动态链接库的形式,有利于JavaVM工程调用该工程中的导出函数。第三部分为主程序,JVM工程。该工程负责解析并设置虚拟机运行参数,调用JavaVM工程的虚拟机实现类来启动虚拟机。该工程为可执行文件。3.1 我们将主程序与虚拟机工程分离,底层平台实现相关与实现无关部分代码分离,使MiniJavaVM虚拟机的实现更具层次感。同时,也具有了更好的可扩充性JVM工程JVM工程负责解析并设置虚拟机运行参数,调用JavaVM工程的虚拟机实现类来启动虚拟机。JVM工程所要完成的任务可以用图3.1.1表示:初始化虚

36、拟机参数图3.1.1JVM工程流程JVM工程只是调用JavaVM工程中导出的JavaVM类,设置其参数及入口类,所有Java虚拟机的运行工程交由JavaVM类完成。3.2 JavaVM工程JavaVM工程实现了一个Java虚拟机的所有功能,包括定义虚拟机的数据类型和字长,实现虚拟机栈结构,组织方法区和堆,装载和解析类,实现执行引擎,调用非本地方法,实现多线程,处理异常等。但这个工程不负责虚拟机在执行过程中需要调用的本地方法的实现。由于本地方法总是与Java虚拟机实现的底层平台相关的,因此这个工程只负责处理与底层平台实现不相关的部分,而将与底层平台实现相关的部分交给另外一个工程JavaNativ

37、eCall工程。3.2.1 Java虚拟机的数据类型和字长考量Java虚拟机是通过某些数据类型来执行计算的,数据类型及其运算都是由Java虚拟机规范严格定义的。数据类型可以分为两种:基本类型和引用类型。基本类型的变量持有原始值,而引用类型的变量持有引用值,图3.2.1描述了Java虚拟机中的数据类型:引用类型基本类型图3.1.1Jav睫拟机中的数据类型Java虚拟机规范定义了每一种数据类型的取值范围,但是没有定义它们的位宽。存储这些类型的值所需的占位宽度,是由具体的虚拟机实现的设计者决定的。Java语言中的所有基本类型同样也是Java虚拟机中的基本类型。但boolean有点特别,当编译器把Ja

38、va源码编译为字节码时,它会用int或byte来表示boolean。在Java虚拟机中,false是由整数零来表示的,所有非零整数都表示true。涉及boolean值的操作则会使用int。表3.2.1Java虚拟机数据类型的取值范围类型范围ByteShortIntLongCharFloatDoubleReturnAddressReference8比特,带符号,二进制补码16比特,带符号,二进制补码32比特,带符号,二进制补码64比特,带符号,二进制补码16比特,不带符号,Unicode字符32比特,IEEE754标准单精度浮点数64比特,IEEE754标准单精度浮点数问一方法中某操作码的地址堆

39、中对某对象的引用,或者是nullJava虚拟机中,最基本的数据单元就是字(word),它的大小是由每个虚拟机实现的设计者来决定的。字长必须足够大,至少是一个字单元就足以持有byte、short、int、char、float、returnAddress或者reference类型的值,而两个字单元就足以持有long或者double类型的值。因此,虚拟机实现的设计者至少得选择32位作为字长,或者选择更为高效的字长大小。通常根据底层主机平台的指针长度来选择字长。Java虚拟机规范中,关于运行时数据区的大部分内容,都是基于“字”这个抽象概念的。比如,关于栈帧的两个部分一一局部变量和操作数栈一一都是按照“

40、字”来定义的。这个内容区域能够容纳任何虚拟机数据类型的值,当把这些值放到局部变量或者操作数栈中时,它将占用一个或两个字单元。错误!未定义书签。在我们的JavaVM工程中,对Java虚拟机的数据类型和字长的定义如下:#definenull0typedefunsignedlongword;typedefunsignedcharjava_bool;typedefunsignedshortjava_char;typedefcharjava_byte;typedefshortjava_short;typedeflongjava_int;typedef_int64java_long;typedeffloa

41、tjava_float;typedefdoublejava_double;typedefvoidjava_void;typedefwordjava_reference;定义字长,32位无符号long型为word定义Java数据类型图3.2.2JavaVM工程中数据类型定义3.2.2 JavaVM类JavaVM类是JavaVM工程中最重要的一个类,这个类定义了Java虚拟机应该实现的功能,所有Java虚拟机相关的功能对应于通过调用该类的相应方法来实现。为了定义JavaVM类,我们必须定义其他一些辅助类。这些辅助类包括:JavaThread类:负责管理虚拟机线程CClassFile类:负责读取Ja

42、vaClass文件的内容JavaClassInfo类:负责根据CClassFile类的内容生成该java类的类信息JavaArrayInfo类:负责生成某一类型的数组信息JavaClass类:负责找出要装载的javaclass文件,并将文件内容作为二进制流传给CClassFile类Cp_xxxxxxxx类:负责维护Class文件中常量池的内容Attr_xxxxxxxx类:负责维护Class文件常量池中attr_info相关的内容Memxxxxxxx类:负责虚拟机的内存管理,包括分配内存和进行垃圾收集JavaVM类的接口定义如下:/为Java虚拟机起一个新的线程,返回值为这个新线程的指针Java

43、Thread*CreateNewJavaThread();/得到当前线程的java/lang/Thread实例引用wordGetCurrentThreadReference()const;/根据Thread的reference来判断该Thread是否还是aliveboolIsThreadAlive(wordobjref);设置虚拟机入口的JavaClass类boolSetExecuteClassName(constchar*szClassName);/运行Java虚拟机boolExecute();voidPushNewStackFrame(intnMax_local);voidPushStac

44、kFrame(StackFrame*pStackFrame);voidPopStackFrame();voidPushValue(wordvalue);wordPopValue();boolIsStackEmpty();boolIsStackFrameEmpty();StackFrame*GetCurrentStackFrame();/通过class名得到该class的内容CClassFile*GetClassFileByName(constchar*szClassName);/通过引用得到该引用对应的Class的内容CClassFile*GetClassFileByReference(wor

45、dref);/装载一个指定的Java类CClassFile*LoadClass(constchar*szClassName);/根据引用得到一个java数组的信息JavaArrayInfo*GetArrayInfoByReference(wordarrayref);/根据引用得到一个javaString类型浦字符串值stringGetStringByStringReference(wordref);/将一个String类型的引用与String的内容在虚拟机内建立关联voidSetStringByStringReference(wordref,conststring&s);/根据clas

46、s的名称得到对应的表示该class的Class类型的实例的引用多线程相关接口虚拟机启动相关接口虚拟机栈相关操作接口Javal用与Class内容相关部分接口wordGetClassReferenceByClassName(conststring&szClassName);垃圾收集相关接口分配空间对内存空间进行操作一对局部变量进行操作对类的静态字段进行操作3类实例的字段进行操作/GC开始前先将遍历的指针指向第一个要访问的元素voidBeginStackTraversal();/是否对栈的访问结束boolIsTraversalFinished();/返回下一个栈中的元素wordGetNext

47、StackValue();/该引用是否需要调用Finalize函数boolNeedFinalize(wordref);/调用该引用的Finalize函数voidFinalize(wordref);/对于已经调用过Fianlize函数的引用,作标记,/使下次不再被Finalize掉voidRemoveFromFinalized(wordref);/为一个JavaClass类的实例分配空间,返回值为referencewordAllocateClassMemory(JavaClassInfo*pClassInfo);/为一个Java数组分配空间,返回值为referencewordAllocateAr

48、rayMemory(JavaArrayInfo*pArrayInfo);/为一个Java某个类的静态字段分配空间,返回值为referencewordAllocateStaticFieldMemory(JavaClassInfo*pClassInfo);/把pSrc的内容写size大小的数据到pDst中voidWriteMemory(wordobjref,intoffset,constvoid*pValue,size_tsize);/读pSrc中size大小的数据到pDst中voidReadMemory(wordobjref,intoffset,void*pValue,size_tsize);/

49、得到指定index的局部变量的值wordGetLocalVariable(intindex)const;/设置指定index的局部变量的值voidSetLocalVariable(intindex,wordvalue);/设置一个实例的某一指定非静态字段的值boolWriteInstanceNonStaticField(wordobjref,constchar*szFieldName,void*pValue,size_tsize);/读取一个实例的景一指定静态字段的值boolReadInstanceNonStaticField(wordobjref,constchar*szFieldName,

50、void*pValue,size_tsize);/设置一个类的静态字段的值boolWriteClassStaticField(constchar*szClassName,constchar*szFieldName,void*pValue,size_tsize);/读取一个类的静态字段的值一boolReadClassStaticField(constchar*szClassName,constchar*szFieldName,void*pValue,size_tsize);我们的JavaVM类内部组织如图3.2.3所示:JavaVM图3.2.3JavaVM类内部组织结构其中线程部分设计如图3.2

51、.4所示:某一栈帧某一线程栈帧栈帧图3.2.4MiniJavaVM线程组织通过上面设计,使用JavaVM类来表示Java虚拟机,使用一个唯一的JavaVM的全局变量来代表运行中的Java虚拟机;使用链表来存储在Java虚拟机上运行的所有线程,并保留一个指向当前线程的指针;使用链表来存储已经装载的class文件的信息,并保留一个指向入口class的指针,以找到正确的main()入口;在JavaVM类中定义内存管理模块的接口,通过调用这些接口来分配并读写内存,并把类信息同相应的返回的引用值联系起来;在JavaVM类中定义垃圾收集模块的接口,通过这些接口来进行垃圾收集。3.3 JavaNativeC

52、all工程JavaNativeCall工程为本地方法实现部分工程。此工程负责本地方法接口(JNI)的声明和实现。该工程开发为动态链接库的形式,有利于JavaVM工程调用该工程中的导出函数,真正做到本地方法调用的功能。为了实现这个工程,这里参考了Kaffe中关于JNI实现部分的代码。Kaffe是一个功能强大的Java虚拟机,它包括Java2平台的子集,标准JavaAPI和工具来提供Java运行时环境。错误!未定义书签。MiniJavaVM的本地方法接口(JNI)部分主要是参考了Kaffe中对本地方法接口的定义。我们的MiniJavaVM的本地方法接口的实现定义了如下类型:typedefjava_

53、referencejava_object;typedefjava_objectjava_class;typedefjava_objectjava_string;typedefjava_objectjava_array;typedefjava_arrayjava_boolArray;typedefjava_arrayjava_byteArray;typedefjava_arrayjava_charArray;typedefjava_arrayjava_shortArray;typedefjava_arrayjava_intArray;typedefjava_arrayjava_longArray

54、;typedefjava_arrayjava_floatArray;typedefjava_arrayjava_doubleArray;typedefjava_arrayjava_objectArray;JNI部分新增的Javatl型定义所有JNI函数的声明均按照“MiniJavaVM咆名+类名+方法名+参数列表”的格式声明。如java.lang.System类的本地方法registerNatives()的声明如下:java_void_MiniJava_java_lang_System_registerNatives(JavaVM*pJVM,java_classclsref);具体调用时,只要

55、在装载该方法所在的动态链接库后再得到该方法的地址,将参数压栈,调用这个方法,就能完成这个方法的调用,也就实现了Java本地方法。第四章类的装载和解析4.1 JavaClass文件Javaclass文件中包含了Java虚拟机所需知道的、关于类或接口的所有信息。Javaclass文件是8位字节的二进制流。数据项按顺序存储在class文件中,相邻的项之间没有任何间隔,这样可以使class文件更紧凑。占据多个字节空间的项按照高位在前的顺序分为几个连续的字节存放。错误!未定义书签。和Java类的可以包含多个不同的字段、方法、方法参数、局部变量等一样,Javaclass文件也能够包含许多不同大小的项。在c

56、lass文件中,可变长度项的大小和长度位于其实际数据之前。这个特性使得class文件流可以从头到尾被顺序解析,首先读出项的大小,然后读出项的数据。Class文件的基本类型如下,所有存储在u2,u4,u8项中的值,在class文件中以高位在前的形式出现。表4.1.1class文件基本类型u11个字节,无符号类型u22个字节,无符号类型u44个字节,无符号类型u88个字节,无符号类型可变长度的ClassFile表中的项,如表4.1.2所示:表4.1.2ClassFile表的格式类型名称数量U4Magic1U2Minor_version1U2Major_version1U2Constant_pool_count1Cp_infoConstan

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论