Java虚拟机的设计和实现_第1页
Java虚拟机的设计和实现_第2页
Java虚拟机的设计和实现_第3页
Java虚拟机的设计和实现_第4页
Java虚拟机的设计和实现_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

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

文档简介

Java 虚拟机的设计和虚拟机的设计和 实现实现 目目 录录 第一章第一章绪论绪论 6 1 1Java 及及 Java 虚拟机虚拟机 6 1 2Java 虚拟机的体系结构虚拟机的体系结构 7 1 3MiniJavaVM 的功能的功能 10 1 4MiniJavaVM 的运行环境及开发工具的运行环境及开发工具 12 第二章第二章系统设计系统设计 13 2 1唯一的虚拟机唯一的虚拟机 MiniJavaVM 13 2 2MiniJavaVM 的构成要素的构成要素 13 2 2 1虚拟机总体框架虚拟机总体框架 13 2 2 2命令参数解析模块命令参数解析模块 15 2 2 3类的装载和解析模块类的装载和解析模块 15 2 2 4内存管理模块内存管理模块 16 2 2 5执行引擎模块执行引擎模块 17 2 2 6方法调用模块方法调用模块 18 2 2 7异常处理模块异常处理模块 19 第三章第三章虚拟机框架的实现虚拟机框架的实现 21 3 1JVM 工程工程 22 3 2JavaVM 工程工程 23 3 2 1Java 虚拟机的数据类型和字长考量虚拟机的数据类型和字长考量 23 3 2 2JavaVM 类类 24 3 3JavaNativeCall 工程工程 29 第四章第四章类的装载和解析类的装载和解析 30 4 1Java Class 文件文件 30 4 2Class 文件在文件在 MiniJavaVM 中的数据结构表示中的数据结构表示 32 4 3类的装载和解析类的装载和解析 36 第五章第五章内存管理内存管理 41 5 1对象 堆 方法区的管理对象 堆 方法区的管理 41 5 2MiniJavaVM 的垃圾回收过程的垃圾回收过程 44 第六章第六章执行引擎执行引擎 Java 操作码实现操作码实现 47 6 1Java 虚拟机中的操作码功能分类虚拟机中的操作码功能分类 47 6 2操作码功能实现操作码功能实现 JavaOperatorExecute 类类 49 第七章第七章方法调用的实现方法调用的实现 50 7 1Java 中的方法调用中的方法调用 50 7 2非本地方法的实现非本地方法的实现 51 7 3本地方法的实现本地方法的实现 52 7 3 1Java 中的本地方法中的本地方法 52 7 3 2NativeMethod access 类类 54 7 3 3如何处理本地方法可变参数问题如何处理本地方法可变参数问题 54 第八章第八章异常的实现异常的实现 56 8 1Java 中的异常中的异常 56 8 2异常在异常在 MiniJavaVM 中的实现中的实现 56 第九章第九章验证验证 MiniJavaVM 的正确性的正确性 58 9 1MiniJavaVM 的使用方法的使用方法 58 9 2测试操作码实现的正确性测试操作码实现的正确性 61 9 2 1方法调用的正确性方法调用的正确性 61 9 2 2数学运算的正确性数学运算的正确性 64 9 2 3控制流语句的正确性控制流语句的正确性 65 9 3测试本地方法调用测试本地方法调用 66 9 4测试异常处理测试异常处理 67 第十章第十章不足与后续工作不足与后续工作 69 10 1本地方法本地方法 69 10 2I O 操作操作 69 10 3多线程多线程 69 10 4效率效率 69 致谢致谢 71 参考文献参考文献 72 摘要 本文叙述了 Java 虚拟机 JVM 的概念及如何设计和实现一个 Java 虚拟机 MiniJavaVM 着重介绍了虚拟机的体系结构及如何设计和实现这个体系结构 在 探讨虚拟机的设计过程中详细介绍了 MiniJavaVM 虚拟机各部分的设计 包括类的 装载和解析 内存管理 执行引擎 方法调用和异常处理部分 最后通过测试 MiniJavaVM 来验证设计和实现的正确性 关键词 Java 虚拟机 JVM 字节码 类装载 执行引擎本地方法 MiniJavaVM adesignand implementation of a Java Virtual Machine Abstract This paper describes the conception of Java Virtual Machine JVM and how to design and implement a Java Virtual Machine MiniJavaVM It emphasizes the architecture of JVM and how to design and implement the architecture It describes the details about each part of JVM when discussing how to design the JVM including class loading and resolution memory management execution engine method invoking and exception handling At last the correctness of the design and implementation is validated by testing MiniJavaVM Keywords Java Virtual Machine JVM byte code Class loading execution engine Native Method 第一章第一章绪论绪论 1 1Java 及及 Java 虚拟机虚拟机 说起 Java 人们首先想到的是 Java 编程语言 然而事实上 Java 是一种技术 它由 四方面组成 Java 编程语言 Java 类文件格式 Java 虚拟机和 Java 应用程序接口 Java API 它们的关系如下图所示 1 图1 1 1 Java四个方面的关系 运行期环境代表着 Java 平台 开发人员编写 Java 代码 java 文件 然后将之编译 成字节码 class 文件 最后字节码被装入内存 一旦字节码进入虚拟机 它就会被解释 器解释执行 或者是被即时代码发生器有选择的转换成机器码执行 从上图也可以看出 Java 平台由 Java 虚拟机和 Java 应用程序接口搭建 Java 语言则是进入这个平台的通道 用 Java 语言编写并编译的程序可以运行在这个平台上 这个平台的结构如下图所示 1 图1 1 2 Java平台结构 在 Java 平台的结构中 可以看出 Java 虚拟机 JVM 处在核心的位置 是程序与底 层操作系统和硬件无关的关键 它的下方是移植接口 移植接口由两部分组成 适配器和 Java 操作系统 其中依赖于平台的部分称为适配器 JVM 通过移植接口在具体的平台和操 作系统上实现 在 JVM 的上方是 Java 的基本类库和扩展类库以及它们的 API 利用 Java API 编写的应用程序 application 和小程序 Java applet 可以在任何 Java 平台上运行 而无需考虑底层平台 就是因为有 Java 虚拟机 JVM 实现了程序与操作系统的分离 从而 实现了 Java 的平台无关性 1 什么是 Java 虚拟机 Java 虚拟机是运行所有 Java 程序的抽象计算机 它仅仅是由一 个规范来定义的抽象的计算机 当提及 Java 虚拟机 时 可能指的是如下三种不同的东 西 抽象规范 一个具体的实现 一个运行中的虚拟机实例 2 Java 虚拟机负责 Java 程序设计语言的内存安全 平台无关和安全特性 Java 虚拟机 屏蔽了与具体操作系统平台相关的信息 使得 Java 语言编译程序只需生成在 Java 虚拟机上 运行的目标代码 字节码 就可以在多种平台上不加修改地运行 Java 虚拟机 JVM 在多 个平台上实现统一语言 Java 之所以得以大行其道 除了它是一门面向对象 构造精美的 语言之外 更重要的原因在于 它摆脱了具体机器的束缚 使跨越不同平台编写程序成为 可能 1 2Java 虚拟机的体系结构虚拟机的体系结构 在 Java 虚拟机规范中 一个虚拟机实例的行为是分别按照子系统 内存区 数据类型 以及指令这几个术语来描述的 这些组成部分一起展示了抽象的虚拟机的内部抽象体系结 构 但是规范中对它们的定义并非是要强制规定 Java 虚拟机实现内部的体系结构 更多的 是为了严格地定义这些实现的内部特征 规范本身通过定义这些抽象的组成部分以及它们 之间的交互 来定义任何 Java 虚拟机实现都必须遵守的行为 每个 JVM 都有两种机制 一 个是装载具有合适名称的类 类或是接口 叫做类装载子系统 另外的一个负责执行包含 在已装载的类或接口中的指令 叫做运行引擎 每个 JVM 又包括方法区 堆 Java 栈 程 序计数器和本地方法栈这五个部分 这几个部分和类装载机制与运行引擎机制一起组成了 Java 虚拟机的体系结构 图 1 2 1 描述了 Java 虚拟机的结构框图 包括在规范中描述的主要子系统和内存区 类装载器子系统 方法区堆Java栈PC寄存器 本地方法 栈 执行引擎 Class 文件 运行时数据区 本地方 法库 本地方法接口 图1 2 1 Java虚拟机的内部体系结构 每个 Java 虚拟机都有一个类装载器子系统 它根据给定的全限定名来装入类型 类或 接口 同样 每个 Java 虚拟机都有一个执行引擎 它负责执行那些包含在被装载类的方 法中的指令 Java 虚拟机的运行时数据区存储了许多运行时数据 例如 字节码 从已装载的 class 文件中得到的其他信息 程序创建的对象 传递给方法的参数 返回值 局部变量 以及运算的中间结果等 Java 虚拟机把这些东西都组织到几个 运行时数据区 中 以便 于管理 某些运行时数据区是由程序中所有线程共享的 还有一些则只能由一个线程拥有 每 个 Java 虚拟机实例都有一个方法区及一个堆 它们是由该虚拟机实例中所有线程共享的 当虚拟机装载一个 class 文件时 它会从这个 class 文件包含的二进制数据中解析类型信 息 然后把这些类型信息放到方法区中 当程序运行时 虚拟机会把所有该程序在运行时 创建的对象都放到堆中 图 1 2 2 描述了这些内存区域 类 数 据 对象 方法区堆 图1 2 2 由所有线程共享的运行时数据区 类 数 据 类 数 据 类 数 据 类 数 据 类 数 据 对象 对象 对象 对象 对象 对象 对象 当每一个线程被创建时 它都将得到它自己的 PC 寄存器以及一个 Java 栈 如果线程 正在执行的是一个 Java 方法 非本地方法 那么 PC 寄存器的值将总是指示下一条将被执 行的指令 而它的 Java 栈则总是存储该线程中 Java 方法调用的状态 包括它的局部变 量 被调用时传进来的参数 它的返回值 以及运算的中间结果等 而本地方法调用的状 态 则是以某种依赖于具体实现的方式存储在本地方法栈中 也可能是在寄存器或其他某 些与特定实现相关的内存区中 Java 栈是由许多栈帧 stack frame 组成的 一个栈帧包含一个 Java 方法调用的状 态 当线程调用一个 Java 方法时 虚拟机压入一个新的栈帧到该线程的 Java 栈中 当该 方法返回时 这个栈帧被从 Java 栈中弹出并抛弃 Java 虚拟机没有寄存器 其指令集使用 Java 栈来存储中间数据 这样设计的原因是 为了保持 Java 虚拟机的指令集尽量紧凑 同时也便于 Java 虚拟机在那些只有很少通用寄 存器的平台上实现 另外 Java 虚拟机的这种基于栈的体系结构 也有助于运行时某些虚 拟机实现的动态编译器和即时编译器的代码优化 图 1 2 3 描绘了 Java 虚拟机为每个线程创建的内存区 这些内存区是私有的 任何线 程都不能访问另一个线程的 PC 寄存器或者 Java 栈 3 线程1 线程2 线程3 PC寄存器 栈帧 线程1 栈帧 栈帧 栈帧 栈帧 线程2 栈帧 栈帧 栈帧 线程3 栈帧 线程3 本地方法栈 Java栈 图1 2 3 线程专有的运行时数据区 1 3MiniJavaVM 的功能的功能 能够装载并解析 java class 文件 对于已经编译好的 java class 文件 能够读取该 class 文件的内容 装载该类 并保 存在程序内部的数据结构中 当在程序运行的过程中需要解析该类时 进行解析 并替换 符号引用为直接引用 在完成虚拟机的初始化后 能够找到 main 函数并执行程序 Error Reference source not found 对于指定的入口类 在虚拟机完成了初始化后 寻找该类的 main 方法 如果找到 则执行该方法 否则抛出异常 虚拟机运行中止 支持 Java 虚拟机规范中规定的 200 多个操作码的功能 实现了 Java 虚拟机的 200 多个操作码的功能 由此使 MiniJavaVM 这个虚拟机模拟 Java 虚拟机的功能成为可能 这 200 多个操作码包括 栈和局部变量操作指令 将常量池入指令 从栈中的局部变量中装载值指令 将栈中的值存入局部变量指令 通用栈操作指令 类型转换指令 整数运算指令 逻辑运算指令 移位操作指令 按位布尔运算指令 浮点运算指令 对象和数组指令 对象操作指令 数组操作指令 控制流指令 条件分支指令 比较指令 无条件转移指令 表跳转指令 异常指令 finally 子句指令 方法调用与返回指令 方法调用指令 方法返回指令 线程同步指令 具有内存管理和垃圾收集机制 Java 虚拟机对内存的管理使得 java 程序具有很高的安全性 程序员不用担心内存访 问越界问题 也不用为在合适的时候释放分配的空间而费心 垃圾收集机制的存在解决何 时回收不用的内存和如何回收内存的问题 支持非本地方法调用 按照 Java 虚拟机规范中的要求来设置非本地方法的调用情况 包括参数压栈 分配局 部变量空间 压入方法调用的栈桢等 支持本地方法调用 Java 虚拟机中所有与本地方法相关的部分都重新写过 以动态链接库的形式为 MiniJavaVM 工程提供支持 MiniJavaVM 的本地方法只实现最基本的功能 不再负责虚拟 机的安全机制 支持异常处理 有了异常处理 就能够在程序运行时平稳处理意外情况 根据 Java class 文件中的异 常表 MiniJavaVM 程序支持所有的异常处理 并在不能解决异常时输出异常信息 虚拟机 停止运行 能够运行与 I O 无关的完整 Java 程序 并提供参数供查看运行效果 提供了 version showversion help verbose 命令 version 命令显示 MiniJavaVM 的版本信息 然后退出 showversion 命令显示 MiniJavaVM 的版本信息 然后继续运行 Java 程序 help 命令显示帮助信息 verbose 命令输出详细数据显示运行过程 1 4MiniJavaVM 的运行环境及开发工具的运行环境及开发工具 开发平台 Windows XP 2003 开发语言 ANSI C C 开发工具 Visual Studio C Visual S 运行平台 Windows XP 2000 2003 第二章第二章系统设计系统设计 2 1唯一的虚拟机唯一的虚拟机 MiniJavaVM 一个运行的 Java 虚拟机实例的天职就是 负责运行一个 Java 程序 当启动一个 Java 程序时 一个虚拟机实例也就诞生了 当该程序关闭退出 这个虚拟机实例也就随之消亡 如果在同一台计算机上同时运行三个 Java 程序 将得到三个 Java 虚拟机实例 每个 Java 程序实例都运行于它自己的 Java 虚拟机实例中 Error Error ReferenceReference sourcesource notnot found found 为此 需要有一种机制保证在运行过程中只有一个 Java 虚拟机的实例产生 首先要定 义表示 Java 虚拟机的类 然后保证这个类有只一个实例 一种可以供选择的方案是使用 Singleton 设计模式 保证 Java 虚拟机实例在整个程序运行过程中只有一个 另一种是可 以考虑 MFC Microsoft Fundamental Class 中唯一的全局变量 theApp 来表示程序运行的 实例 通过 AfxGetApp 的方法来得到该唯一的全局变量的指针 然后在此基础上进行操 作 在这里 我们选择 MFC 方式定义唯一的全局变量来表示 Java 虚拟机的运行实例 可以 在程序进入 main 函数前完成虚拟机的初始化 通过定义一个全局函数来返回虚拟机实例 的指针 2 2MiniJavaVM 的构成要素的构成要素 2 2 1虚拟机总体框架虚拟机总体框架 我们的 MiniJavaVM 的框架合理地组织了虚拟机运行时所需的各模块 将各模块的输入 与输出有效地结合在一起 使这些模块组合在一起完成了 Java 虚拟机的功能 这些模块包 括 命令参数解析模块 类的装载和解析模块 内存管理模块 执行引擎模块 方法调用 模块 异常处理模块 多线程处理模块 未完成 我们的 MiniJavaVM 总的组织方式如图 2 2 1 所示 命令参数解析模块 根据MiniJavaVM后的参数来设定虚拟机 的运行模式及输出信息 内存管理模块 为类的实例及静态字段分配空间 并在虚拟机内维护实例 当空间 不足时启动垃圾回收机制来回收 内存 类的装载和解析模块 装载指定名称的java类 并采用迟解析 的方式在需要时解析该类 类的信息维 护在虚拟机的一个数据结构中 执行引擎模块 解释执行java虚拟机的200多个操作码 方法调用模块 当调用一个方法时 本地方法与非本地方法 使用此模块 包括找到指定方法全限定名的方 法与处理参数压栈及调用方法并返回的过程 异常处理模块 当虚拟机抛出异常且不能处理时 记录异常信息 在程序退出前输出 多线程处理模块 在语言级提供多线程支持 虚拟 机退 出 虚虚 拟拟 机机 输入命令 图2 2 1 MiniJavaVM的模块组织 其中除命令参数解析模块外 其他模块一起构成了完整的 MiniJavaVM 虚拟机 这些模 块之间协同合作 完成了虚拟机的功能 其中命令参数解析模块负责解析命令 根据 MiniJavaVM 后的参数来设定虚拟机的运行模式及输出信息 类的装载和解析模块能从 class 文件或是 rt jar 文件中装载指定名称的 Java 类 并采用迟解析的方式在需要时解 析该类 类的信息维护在虚拟机的一个数据结构中 内存管理模块负责为类的实例及静态 字段分配空间 并在虚拟机内维护类的实例和静态字段 当虚拟机空间不足时会启动垃圾 回收机制来回收内存 执行引擎模块负责解释执行 200 多个操作码 解释的过程包括对栈 桢 栈 PC 局部变量区的修改 多线程处理模块负责维护虚拟机内的表示线程的数据结 构 在语言级提供多线程支持 方法调用模块负责处理方法调用过程 对于非本地方法 包括找到调用方法的指针 新建栈桢 将方法参数设置在新栈桢的局部变量区 调用方法 并将返回值压栈的过程 对于本地方法 包括找到调用方法的指针 将方法参数用汇编的 方式压栈 调用本地方法并将返回值压栈的过程 异常处理模块负责处理虚拟机抛出的异 常 记录异常产生处的异常信息 并试图通过查找当前方法的异常表来处理异常信息 如 果能够通过异常表找到处理异常的代码 则修改 PC 的值使虚拟机处理当前异常 否则 当 虚拟机不能处理该异常时 输出异常信息 然后终止虚拟机的运行 通过这几个模块的协 同合作 我们的 MiniJavaVM 虚拟机能够很好地模拟 Java 虚拟机的功能 2 2 2命令参数解析模块命令参数解析模块 命令参数解析模块负责解析命令行 根据 MiniJavaVM 后的参数来设定虚拟机的运行模 式及输出信息 该模块的设计如图 2 2 2 所示 命令参数解析模块 将命令行参数翻译成虚拟机运行时参数 虚拟机运 行时参数 命令行参数 图2 2 2 命令行参数解析模块 命令参数解析模块在解析完命令行参数后 通过得到虚拟机的唯一实例的指针调用设 置参数的方法来设置虚拟机运行时的参数 2 2 3类的装载和解析模块类的装载和解析模块 类的装载和解析模块负责从 java class 文件或是 rt jar 文件中装载指定名称的 Java 类 并采用迟解析的方式在需要时解析该类 类的信息维护在虚拟机的一个数据结构中 我们的 MiniJavaVM 类的装载和解析模块设计如图 2 2 3 所示 类的装载和解析模块 类的装载和解析过程 Java class文件 Rt jar文件 class文件字节流 读取字节流 中的类信息 生成该Java类在虚 拟机中对应的数据 解析该类的信息 常量池解析 类装载完成 需要解析类信息 图2 2 3 类的装载和解析模块 其中要装载的类文件有两种渠道获得 一种是直接查找相应类的 class 文件 一种是 从 rt jar 文件中得到类的 class 文件的数据 为了统一这两种方式 可以先从这两种方法 中生成类文件的字节流 再交由下一步程序处理 当生成 class 文件的字节流后 通过指 定的模块读取字节流中的信息 生成该 Java 类在虚拟机中对应的数据 这样 类装载的部 分算是完成 在虚拟机运行的过程中 会需要解析类中的常量池 将符号引用替换为直接 引用 2 2 4内存管理模块内存管理模块 内存管理模块负责为类的实例及静态字段分配空间 并在虚拟机内维护类的实例和静 态字段 当虚拟机空间不足时会启动垃圾回收机制来回收内存 在 Java 虚拟机中 关于被装载类型的信息存储在一个逻辑上称为方法区的内存中 所 有线程共享方法区 因此它们对方法区数据的访问必须被设计为是线程安全的 方法区的 大小不必是固定的 虚拟机可以根据应用的需要动态调整 同样 方法区也不必是连续的 方法区可以在一个堆 甚至是虚拟机自己的堆 中自由分配 另外 虚拟机也可以允许用 户或者程序员指定方法区的初始大小以及最小和最大尺寸等 Error Error ReferenceReference sourcesource notnot found found 方法区也可以被垃圾收集 因为虚拟机允许用户定义的类装载器来动态扩展 Java 程序 因此一些类也会成为程序 不再引用 的类 当某个类变为不再被引用的类时 Java 虚拟机 可以卸载这个类 垃圾收集 从而使方法区占据的内存保持最小 为了简单 我们的 MiniJavaVM 的方法区使用虚拟机自己的堆 不参与垃圾回收 同时 类的静态字段及一些特殊的类的实例 如与每个类相关的 Class 类的实例 也不参与垃圾 回收 我们的 MiniJavaVM 内存管理模块设计如图 2 2 4 所示 内存管理模块 为虚拟机堆分配空间 管理虚拟机堆空间 当空间 不足时进行垃圾回收 分配可回 收的内存 分配不可 回收内存 垃圾收集 内存分配请求 可回收 哈希表管理已 分配的内存 内存不足 完成垃圾收集 内存分配请求 不可回收 分配的内 存 地址 已 作过映 射 图2 2 4 内存管理模块 当 MiniJavaVM 虚拟机请求一个可以被回收的内存空间 比如普通类的实例空间 时 则通过内存管理模块分配可回收的内存 所分配的内存的实地址经过映射后返回给虚拟机 同时已分配的内存地址记录在一张哈希表中 供快速查找所用 如果虚拟机已经没有可分 配的空间 则运行垃圾收集 垃圾收集完成后再分配内存 当虚拟机请求一个不可被回收 的内存空间 比如类的静态字段空间 表示已装载类的 Class 类的实例等 时 通过内存 管理模块分配不可回收内存 所分配的内存的实地址经过映射后返回给虚拟机 同时已分 配的内存地址记录在一张哈希表中 供快速查找所用 当垃圾收集完成后仍没有可分配的 内存地址可用时 虚拟机退出 2 2 5执行引擎模块执行引擎模块 任何 Java 虚拟机实现的核心都是它的执行引擎 在 Java 虚拟机规范中 执行引擎的 行为使用指令集来定义 对于每条指令 Java 虚拟机规范都详细规定了当实现执行到该指 令时应该处理什么 Error Error ReferenceReference sourcesource notnot found found 执行引擎模块负责解释执行 Java200 多个操作码 解释的过程包括对 Java 栈桢 Java 栈 PC 局部变量区的修改 我 们的 MiniJavaVM 执行引擎模块设计如图 2 2 5 所示 执行引擎模块 解释完成操作码的功能 字节码流 判断是否是 Java操作码 按该操作码的功能装 载Java类 分配内存 进行数学运算 修改 Java栈桢 Java栈 PC 局部变量区等 是 否 虚拟机运行异常 取操 作码 结束 无操作码 图2 2 5 执行引擎模块 在调用执行引擎模块时 会传入一字节码流 执行引擎模块负责解释这一字节码流 在解释字节码过程中 Java 虚拟机可能会装载新的 Java 类 分配某个 Java 类的实例 进 行数学运算 修改当前 java 栈桢 Java 栈 PC 局部变量区等 2 2 6方法调用模块方法调用模块 方法调用模块负责处理方法调用过程 对于非本地方法 包括找到调用方法的指针 新建栈桢 将方法参数设置在新栈桢的局部变量区 调用方法并将返回值压栈的过程 对 于本地方法 包括找到调用方法的指针 将方法参数用汇编的方式压栈 调用本地方法并 将返回值压栈的过程 我们的 MiniJavaVM 方法调用模块的设计如图 2 2 6 所示 方法调用模块 Java方法调用 找到该本地方法所 在的动态链接库 装载该模块 新建该方法的Java栈 帧 将参数设置到 局部变量区中 栈 帧压栈 调用方法 的名称和 描述符 调用操作码解 释模块执行该 方法的操作码 该方法的 Java栈帧 出栈 将该方法的 参数压栈 调用该本 地方法 查找该方法 在虚拟机中 对应的数据 结构 图2 2 6 方法调用模块 非本地方法 本地方法 抛出异常 调用异常处理模块 如有异常 虚拟机为每一个调用的 Java 非本地 方法一个新的栈帧 栈帧包括 为方法的局部变 量所预留的空间 该方法的操作数栈 以及特定虚拟机实现需要的其他所有信息 局部变 量和操作数栈的大小在编译时计算出来 并放置到 class 文件中去 然后虚拟机就能够了 解到方法的栈帧需要多少内存 当虚拟机调用一个方法的时候 它为该方法创建恰当大小 的栈帧 再将新的栈帧压入 Java 栈 处理实例方法时 虚拟机从所调用方法栈帧内的操作 数栈中弹出 objectref 和 args 虚拟机把 objectref 作为全局变量 0 放到新的栈帧中 把 所有的 args 作为局部变量 1 2 等处理 Objectref 是隐式传给所有实例方法的 this 指针 对于类方法 虚拟机只从所调用的方法栈帧中的操作数栈中弹出参数 并将它 们放到新的栈帧中去作为局部变量 0 1 2 当 objectref 和 args 对于类方法则只有 args 被赋给新栈帧中的局部变量后 虚拟机把新的栈帧作为当前栈帧 然后将程序计数 器指向新方法的第一条指令 Error Error ReferenceReference sourcesource notnot found found 虚拟机使用一种 与实现相关 的风格调用本地方法 当调用本地方法时 虚拟机不会 将一个新的栈帧压入 Java 栈 当线程进入到本地方法的那一刻 它就将 Java 栈抛在身后 直到本地方法返回以后 Java 栈才被重新调用 这里本虚拟机的实现将使用调用动态链接 库中的方法来实现本地方法调用的过程 2 2 7异常处理模块异常处理模块 异常处理模块负责处理虚拟机抛出的异常 记录异常产生处的异常信息 并试图通过 查找当前方法的异常表来处理异常信息 如果能够通过异常表找到处理异常的代码 则修 改 PC 的值使虚拟机处理当前异常 否则 当虚拟机不能处理该异常时 输出异常信息 然 后终止虚拟机的运行 我们的 MiniJavaVM 异常处理模块的设计如图 2 2 7 所示 异常处理模块 处理异常 异常 抛出 检查本栈帧对 应方法的异常 表 查找是否 有匹配的异常 当前Java 栈帧出栈 没有对应 异常表 还有Java 栈帧 修改当前PC 的值 调用 操作码解释 模块 查找到对应异常表 输出异常 信息 虚 拟机退出 返回调用 模块 Java栈帧 都已出栈 图2 2 7 异常处理模块 第三章第三章虚拟机框架的实现虚拟机框架的实现 Java 虚拟机的体系结构如图 3 1 所示 类装载器子系统 方法区堆Java栈PC寄存器 本地方法 栈 执行引擎 Class 文件 运行时数据区 本地方 法库 本地方法接口 图3 1 Java虚拟机的内部体系结构 实现虚拟机框架 需要考虑以下几点 虚拟机的数据类型和字长 如何实现栈结构 如何装载和解析类 如何调用本地和非本地方法 如何实现执行引擎 如何实现多线程 机如何组织方法区和堆 如何进行垃圾回收 虚拟机如何处理异常 为了解决这些问题 这里我们把 MiniJavaVM 虚拟机的实现总体分为三部分 第一部分为主体部分 JavaVM 工程 这个工程相当于实现了一个 Java 虚拟机的所有 功能 包括定义虚拟机的数据类型和字长 实现虚拟机栈结构 组织方法区和堆 装载和 解析类 实现执行引擎 调用非本地方法 实现多线程 处理异常等 但这个工程不负责 虚拟机在执行过程中需要调用的本地方法的实现 由于本地方法总是与 Java 虚拟机实现的 底层平台相关的 因此这个工程只负责处理与底层平台实现不相关的部分 而将与底层平 台实现相关的部分交给另外一个工程 JavaNativeCall 工程 JavaVM 工程将开发为动态链 接库的形式 有利于别的工程调用这个工程中重要的导出类和导出方法 第二部分为本地方法实现部分 JavaNativeCall 工程 此工程负责本地方法接口 JNI 的声明和实现 该工程将开发为动态链接库的形式 有利于 JavaVM 工程调用该工 程中的导出函数 第三部分为主程序 JVM 工程 该工程负责解析并设置虚拟机运行参数 调用 JavaVM 工程的虚拟机实现类来启动虚拟机 该工程为可执行文件 我们将主程序与虚拟机工程分离 底层平台实现相关与实现无关部分代码分离 使 MiniJavaVM 虚拟机的实现更具层次感 同时 也具有了更好的可扩充性 3 1JVM 工程工程 JVM 工程负责解析并设置虚拟机运行参数 调用 JavaVM 工程的虚拟机实现类来启动虚 拟机 JVM 工程所要完成的任务可以用图 3 1 1 表示 开始 解释命令行参数 初始化虚拟机参数 设置虚拟机入口类 虚拟机执行 结束 图3 1 1 JVM工程流程 JVM 工程只是调用 JavaVM 工程中导出的 JavaVM 类 设置其参数及入口类 所有 Java 虚拟机的运行工程交由 JavaVM 类完成 3 2JavaVM 工程工程 JavaVM 工程实现了一个 Java 虚拟机的所有功能 包括定义虚拟机的数据类型和字长 实现虚拟机栈结构 组织方法区和堆 装载和解析类 实现执行引擎 调用非本地方法 实现多线程 处理异常等 但这个工程不负责虚拟机在执行过程中需要调用的本地方法的 实现 由于本地方法总是与 Java 虚拟机实现的底层平台相关的 因此这个工程只负责处理 与底层平台实现不相关的部分 而将与底层平台实现相关的部分交给另外一个工程 JavaNativeCall 工程 3 2 1Java 虚拟机的数据类型和字长考量虚拟机的数据类型和字长考量 Java 虚拟机是通过某些数据类型来执行计算的 数据类型及其运算都是由 Java 虚拟 机规范严格定义的 数据类型可以分为两种 基本类型和引用类型 基本类型的变量持有 原始值 而引用类型的变量持有引用值 图 3 2 1 描述了 Java 虚拟机中的数据类型 基本类型 数据类型 浮点数类型 整数类型 引用类型 boolean returnAddress 引用 float double byte short int long char 类类型 接口类型 数组类型 图3 1 1 Java虚拟机中的数据类型 Java 虚拟机规范定义了每一种数据类型的取值范围 但是没有定义它们的位宽 存储 这些类型的值所需的占位宽度 是由具体的虚拟机实现的设计者决定的 Java 语言中的所 有基本类型同样也是 Java 虚拟机中的基本类型 但 boolean 有点特别 当编译器把 Java 源码编译为字节码时 它会用 int 或 byte 来表示 boolean 在 Java 虚拟机中 false 是由 整数零来表示的 所有非零整数都表示 true 涉及 boolean 值的操作则会使用 int 表表 3 2 1 Java 虚拟机数据类型的取值范围虚拟机数据类型的取值范围 类型范围 Byte8 比特 带符号 二进制补码 Short16 比特 带符号 二进制补码 Int32 比特 带符号 二进制补码 Long64 比特 带符号 二进制补码 Char16 比特 不带符号 Unicode 字符 Float32 比特 IEEE754 标准单精度浮点数 Double64 比特 IEEE754 标准单精度浮点数 ReturnAddress同一方法中某操作码的地址 Reference堆中对某对象的引用 或者是 null Java 虚拟机中 最基本的数据单元就是字 word 它的大小是由每个虚拟机实现的设 计者来决定的 字长必须足够大 至少是一个字单元就足以持有 byte short int char float returnAddress 或者 reference 类型的值 而两个字单 元就足以持有 long 或者 double 类型的值 因此 虚拟机实现的设计者至少得选择 32 位作 为字长 或者选择更为高效的字长大小 通常根据底层主机平台的指针长度来选择字长 Java 虚拟机规范中 关于运行时数据区的大部分内容 都是基于 字 这个抽象概念 的 比如 关于栈帧的两个部分 局部变量和操作数栈 都是按照 字 来定义的 这个内容区域能够容纳任何虚拟机数据类型的值 当把这些值放到局部变量或者操作数栈 中时 它将占用一个或两个字单元 Error Error ReferenceReference sourcesource notnot found found 在我们的 JavaVM 工程中 对 Java 虚拟机的数据类型和字长的定义如下 define null0 typedef unsigned longword typedef unsigned charjava bool typedef unsigned shortjava char typedef charjava byte typedef shortjava short typedef longjava int typedef int64java long typedef floatjava float typedef doublejava double typedef voidjava void typedef wordjava reference 定义Java 数据类型 定义字长 32 位无符号 long型为 word 图3 2 2 JavaVM工程中数据类型定义 3 2 2JavaVM 类类 JavaVM 类是 JavaVM 工程中最重要的一个类 这个类定义了 Java 虚拟机应该实现的功 能 所有 Java 虚拟机相关的功能对应于通过调用该类的相应方法来实现 为了定义 JavaVM 类 我们必须定义其他一些辅助类 这些辅助类包括 JavaThread 类 负责管理虚拟机线程 CClassFile 类 负责读取 Java Class 文件的内容 JavaClassInfo 类 负责根据 CClassFile 类的内容生成该 java 类的类信息 JavaArrayInfo 类 负责生成某一类型的数组信息 JavaClassFileLoader 类 负责找出要装载的 java class 文件 并将文件内容作为二 进制流传给 CClassFile 类 Cp xxxxxxxx 类 负责维护 Class 文件中常量池的内容 Attr xxxxxxxx 类 负责维护 Class 文件常量池中 attr info 相关的内容 Memxxxxxxx 类 负责虚拟机的内存管理 包括分配内存和进行垃圾收集 JavaVM 类的接口定义如下 为Java虚拟机起一个新的线程 返回值为这个新线程的指针 JavaThread CreateNewJavaThread 得到当前线程的java lang Thread实例引用 word GetCurrentThreadReference const 根据Thread的reference来判断该Thread是否还是alive bool IsThreadAlive word objref 多线程相 关接口 设置虚拟机入口的Java Class类 bool SetExecuteClassName const char szClassName 运行Java虚拟机 bool Execute 虚拟机 启动相 关接口 void PushNewStackFrame int nMax local void PushStackFrame StackFrame pStackFrame void PopStackFrame void PushValue word value word PopValue bool IsStackEmpty bool IsStackFrameEmpty StackFrame GetCurrentStackFrame 虚拟机栈 相关操作 接口 通过class名得到该class的内容 CClassFile GetClassFileByName const char szClassName 通过引用得到该引用对应的Class的内容 CClassFile GetClassFileByReference word ref 装载一个指定的Java类 CClassFile LoadClass const char szClassName 根据引用得到一个java数组的信息 JavaArrayInfo GetArrayInfoByReference word arrayref 根据引用得到一个java String类型的字符串值 string GetStringByStringReference word ref 将一个String类型的引用与String的内容在虚拟机内建立关联 void SetStringByStringReference word ref const string 根据class的名称得到对应的表示该class的Class类型的实例的引用 word GetClassReferenceByClassName const string Java引用 与Class内 容相关部 分接口 GC开始前先将遍历的指针指向第一个要访问的元素 void BeginStackTraversal 是否对栈的访问结束 bool IsTraversalFinished 返回下一个栈中的元素 word GetNextStackValue 该引用是否需要调用Finalize函数 bool NeedFinalize word ref 调用该引用的Finalize函数 void Finalize word ref 对于已经调用过Fianlize函数的引用 作标记 使下次不再被Finalize掉 void RemoveFromFinalized word ref 垃圾 收集 相关 接口 为一个Java Class类的实例分配空间 返回值为reference word AllocateClassMemory JavaClassInfo pClassInfo 为一个Java数组分配空间 返回值为reference word AllocateArrayMemory JavaArrayInfo pArrayInfo 为一个Java 某个类的静态字段分配空间 返回值为reference word AllocateStaticFieldMemory JavaClassInfo pClassInfo 把pSrc的内容写size大小的数据到pDst中 void WriteMemory word objref int offset const void pValue size t size 读pSrc中size大小的数据到pDst中 void ReadMemory word objref int offset void pValue size t size 得到指定index的局部变量的值 word GetLocalVariable int index const 设置指定index的局部变量的值 void SetLocalVariable int index word value 设置一个实例的某一指定非静态字段的值 bool WriteInstanceNonStaticField word objref const char szFieldName void pValue size t size 读取一个实例的某一指定静态字段的值 bool ReadInstanceNonStaticField word objref const char szFieldName void pValue size t size 设置一个类的静态字段的值 bool WriteClassStaticField const char szClassName const char szFieldName void pValue size t size 读取一个类的静态字段的值 bool ReadClassStaticField const char szClassName const char szFieldName void pValue size t size 分配 空间 对内存 空间进 行操作 对局部 变量进 行操作 对类的 静态字 段进行 操作 对类实例 的字段进 行操作 我们的 JavaVM 类内部组织如图 3 2 3 所示 JavaVM 线程列表线程1线程2线程N线程N 1 指向当前线程的指针 JavaVM可用的内存 类数 据 类数 据 类数 据 类数 据 类数 据 方法区堆 对象对象 对象 对象 对象垃圾收集机制 模块 class文件信息 及解析的class 信息列表 JNI模块 指向入口class文件 信息的指针 异常处理模块 图3 2 3 JavaVM类内部组织结构 其中线程部分设计如图 3 2 4 所示 某一线程 栈帧 栈帧 栈帧 栈帧当前栈帧 某一栈帧 局部变量区 字长为32位 局部 变量1 局部 变量2 局部 变量3 局部 变量 N 局部 变量 N 1 操作数栈帧数据区 图3 2 4 MiniJavaVM线程组织 通过上面设计 使用 JavaVM

温馨提示

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

评论

0/150

提交评论