Java虚拟机结构基础研究之一
Posted 中软创新
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java虚拟机结构基础研究之一相关的知识,希望对你有一定的参考价值。
JVM所支持的数据类型和Java语言规范中定义的几乎一样,请注意是几乎一样!也就是原始类型和引用类型,他们可以被存储在变量表中,也可以作为参数传递、被方法返回,更通常的就是成为操作的对象。为什么和Java语言规范中定义的不完全一样呢?因为JVM中有一种Java语言所没有的原始类型:返回地址类型(returnAddress type)。该类型是jsr, ret以及jsr_w指令需要使用到的,它的值是JVM指令的操作码的指针,并且它的值是不能被运行中的程序所修改的。
另外需要提到的就是布尔类型的值,虽然在Java语言中它是完全独立的值,但是在JVM中只提供了对它的有限支持,表现在:
没有单独的操作布尔类型的指令,源代码中的布尔类型的操作在编译以后是作为int类型的值进行操作的。
JVM直接支持布尔数组,newarray指令可以创建布尔数组,而它的访问和修改操作却是使用byte类型的数组的操作指令进行的:baload,bastore。(在JDK1.0,1,1以及1.2中,布尔数组被编码为byte数组,每个元素是8位)
JVM用1代表true,用0代表false,编译器将源代码中的布尔类型映射为JVM中的int类型,而且必须和JVM的要求一致。
另外JVM规范中对于浮点类型的数据有大段的说明,我没有怎么看,主要是讨论JVM的浮点型和IEEE 754的关系的。
关于类型的另外一个需要提一下的是类型检查。JVM期望几乎所有的类型检查已经在运行之前完成了(通常是由编译器进行检查的)而不用JVM自己来检查。原始类型的值不需要被标记或者在运行时被检查以确定他们的类型,同样他们也不用和引用类型的值进行区分,区分工作是由JVM的指令集来完成的,JVM的指令集使用不同指令来区分它要操作的值的类型,例如iadd,ladd
JVM包含对对象的显式支持。类是动态分配的类实例或者是一个数组,JVM中的引用类型就是对一个对象的引用,引用类型的值可以想象为对象的指针,一个对象同时可能存在多个对它的引用,对象总是通过引用被操作、传递或者测试的。
对于引用类型,需要提及的一点就是关于null,它最初是没有运行时类型的,但是它可以被转换为任何类型,而且对于null,JVM并没有要求任何具体的值与之对应。
说完上面这些,我们就开始进入我学习JVM时最想了解的部分了,大家可要打起精神哦。
JVM为运行一个程序定义了几种数据区(Data Area),包括:pc寄存器、JVM堆栈、堆、方法区(Method Area)、运行时常量池(Runtime Constant Pool)以及本机方法堆栈(Native Method Stacks),这些数据区根据其生存期可以分为两种,一种就是和JVM的生存期相同(包括堆和方法区),一种和线程的生存期相同(其它的),和JVM生存期相同的数据区在JVM启动的时候被创建并在JVM退出的时候被销毁,而和线程生存期相同的数据区是每个线程一个的,他们在线程创建的时候被创建,在线程被销毁的时候被销毁。
每个JVM线程还拥有一个私有的JVM堆栈,它存储帧(下一篇文章会讲到)。JVM堆栈和像C这样的传统编程语言中的堆栈是类似的,它保存局部变量和部分结果,并且在方法调用和返回中也担任一些职责。因为除了对帧的压入和弹出操作外,对JVM堆栈不能直接进行操作,因此帧可能是在堆上分配的。如果一个线程中计算所需的JVM堆栈大于允许的大小,JVM会抛出StackOverflowError错误,如果JVM堆栈是可以动态伸缩的,如果需要扩展,但是又没有足够的内存可用或者没有足够的内存为一个新线程创建JVM堆栈,JVM会抛出OutOfMemoryError错误。
JVM只有一个为所有线程所共享的堆,所有的类实例和数组都是在堆中创建的。堆所存储的对象被一个自动存储管理系统回收(也就是我们所熟知的垃圾收集器(gc))。对象不能被显式的释放,JVM假设没有特定类型的自动存储管理系统,存储管理技术可以根据实现者的系统需求进行选择。如果计算所需的内存堆大于自动存储管理系统可以使用的大小。
运行时常量池是类文件中的常量池表的运行时表示,它包含几种常量,范围从编译时就已知的数字常量到运行时必须进行解析的方法和成员引用。运行时常量池扮演的功能类似于传统编程语言中的符号表(symbol table),但是它所包含的数据比典型的符号表更多。
每个运行时常量池从JVM的方法区中分配的,对于特定方法或者接口的运行时常量池是JVM在创建类或者接口的时候创建的。
当创建一个类或者接口时,如果创建运行时常量池需要的内存比方法区中的可用内容更多的内存,JVM会抛出OutOfMemoryError。
关于常量池创建的更多内容以后可能会更详细的讲解。
JVM的实现可能使用传统的堆栈(更通常的讲就是C栈)以支持本机方法(不是使用JAVA语言编写的方法),本机方法堆栈也可以用于在像C语言这样的语言中为JVM指令集实现解析器,对于不能加载本机方法以及自身不依赖传统堆栈的JVM实现而言,它可以不提供本机方法堆栈,如果提供,本机方法堆栈通常在线程创建的时候为每个线程分配(以笔者的理解应该是需要使用本机方法的线程)。如果线程计算所需的内存比本机方法堆栈所允许的大,JVM会抛出StackOverflowError错误,如果本机方法堆栈可以动态伸缩,而当需要扩展的时候又没有足够的内存时,或者没有足够的内容用于创建一个本机方法堆栈,JVM会抛出OutOfMemoryError。
对于上面的这些数据区,JVM规范允许它们的大小是固定尺寸的,也可以是根据计算的需要动态伸缩的,如果是固定尺寸的,其尺寸可以在创建时自主选择。
以上是关于Java虚拟机结构基础研究之一的主要内容,如果未能解决你的问题,请参考以下文章