2004-09-27
第三章:jvm结构
3.1数据类型
基本类型和引用类型
基本值和引用值
数据不需要做标记或者可被检查以确定类型。也就导致jvm的指令集是针对特定类型的值的。
jvm包含对对象的显式支持(引用类型)
3.2基本类型和值
基本类型--returnAddress类型(jvm指令的操作码的指针,不是java类型)
--数值类型--整型--byte
--short
--int
--long
--浮点型--float
--double
--char
jvm中没有boolean类型,java中的boolean类型的操作被翻译为int类型进行操作。
问题:在数值类型中提及的NaN值对应于java里的什么情况
3.3引用类型和值
有三种引用类型:类类型,接口类型,数组类型
3.4字
jvm中没有指定数据类型的存储器大小,只是指定了一个“字”的概念,一个字足以持有byte,int,char,short,float,returnAddress,refrence的值,两个字足够大持有double,long的值。
一般来说,一个字的大小是主机平台的一个指针的大小,32位机上,字是32位,64位机上,字是64位的,但这是实现决定的,而不是jvm规范决定的。
3.5运行期数据
pc(程序计数器)寄存器:
每个jvm线程有自己的pc寄存器,在任何点,每个jvm线程执行一个单个方法的 代码,这个方法被称为那个线程的当前方法。如果方法是native,则pc寄存器的值没有定义,如果不是,则pc寄存器中存放当前正在执行的jvm指令的地址。
pc寄存器占一个字宽。
栈:
每个jvm线程都有私有的栈。等价于传统语言的栈,它持有局部变量和部分结果。并参与部分方法的调用和返回。(由于java框架是可以堆分配的,所以java的栈的存储空间可以是不连续的)
java栈可以是固定大小或者是动态的。jvm实现可以向程序员提供对java栈的初始大小以及动态情况下的最大和最小值的控制。
如果固定大小而且线程需要的栈大于栈的大小,则出现stackoverflowError
如果动态大小但存储器没有足够空间,则出现outOfMemoryError
Sun的jdk1.0.2版jvm实现中,java栈是不连续、动态的,不收缩,在线程消亡时被回收。java栈的大小的限制可以在jvm启动时用“-oss”标志设置。
堆:
java有一个所有线程共享的堆。堆是用于分配所有类实例和数组的运行期数据区。
堆在jvm启动时创建,由garbage collector回收。
堆可以是固定的,也可以动态扩展,并且支持自动收缩,存储器无需连续。
jvm实现可以向程序员提供堆初始大小以及动态情况下的最大和最小值的控制。
如果要求的堆比系统能够拥有的堆大,则出现OutOfMemoryError
Sun的jdk1.0.2中,堆是动态的,从不收缩它的堆,它的初始值和最大值在启动时用“-ms”和“-mx”指定。
方法区:
方法区类似于传统语言中编译后代码的存储区,存储每个类结构例如:常数池、域、方法数据。
方法区是虚拟机建立的时候启动的,逻辑上是垃圾回收实现的一部分,但可以不实现。
方法区可以固定大小,可以动态,可以收缩,无需连续存储器。
jvm实现可以向程序员提供方法区初始大小以及动态情况下的最大和最小值的控制。
outofmemory异常
sun的jdk1.0.2中,仿佛去是动态的,不收缩的,不提供程序员对其最大最小值的控制。
常数池:
常数池是每个类或接口的constant_pool的运行期表示。功能类似于传统语言的符号表,但含更宽的数据范围。(详细见第五章)
自身方法栈(估计应该是native method stack)
其管理和普通栈类似,每个线程一个,线程创建时创建,只是使用非java的native语言(如C)写成,以支持native方法。
Sun的jdk1.0.2版jvm实现中,java栈是固定大小。java栈的大小的限制可以在jvm启动时用“-oss”标志设置。
3.6框架
jvm frame用于存储数据和部分结果,以及动态链接,返回方法的值,和调度异常。
每次java方法调用时创建一个新的框架,当方法结束的时候,框架撤销。框架从创建它的线程的栈里分配,每个框架有自己的局部变量集和操作数栈(这些可以一次分配,因为都是编译期可知的)。
对于一个给定线程的任何点,只有一个活跃框架,称为当前框架,局部变量和操作数栈上的操作总是引用当前框架。
局部变量:
每个jvm frame包含一组局部变量,局部变量总是一个字宽,long型,double型存为两个局部变量。
操作数栈:
每个jvm frame包含一个操作数栈,绝大多数java操作从当前操作数栈取值。
动态连接:
jvm frame通过包含一个对当前类的常数池的引用来达到动态链接的目的,java 的class文件仍然可以使用符号引用访问变量或方法。
java中的i=i++从这一章来理解应该是和框架(jvm frame)这个概念有关,也就是++操作符被实现成为了一个方法,而不是一个虚拟机指令,这样就可以解释了,但是目前还没有看到有++操作符应该被实现为一个方法的说明,另外java的方法调用是值传参的,这种情况应该也不会出现值回写的情况.
看至3。6结束。
3.7对象的表示
jvm不对对象表示要求任何特殊的内部结构。
在sun公司的jdk实现中,对象实例就是指向一个句柄的指针,而这个句柄本身又包括两个指针:1、一个指向包含该对象方法而代表该对象类型的class对象的指针,2、另一个指向在java堆中为该对象实例分配的存储区域。
别的jvm实现可以采用诸如:直接插入高速缓存技术,等。
3.8特殊的初始化方法
实例初始化:构造函数作为具有特殊名字《init》的实例初始化方法出现,方法的名字由编译器提供,这个方法由jvm在内部由invokespecial指令调用,只能使用于未初始化的实例上,不能被java程序员使用。
类和接口的初始化:类和接口的初始化具有特殊的名字《cinit》,方法的名称由编译器提供,该方法由jvm显示调用,从不直接被java代码和jvm指令调用,只是作为类初始化进程的一部分被间接的调用。
3.9异常
异常一层层向上抛,丢弃当前层的操作数栈和局部变量,知道遇到catch为止,如果到顶层还没有catch,当前线程将被结束。
3.10class文件格式
class文件是平台无关格式的二进制文件,class文件格式精确定义了文件的内容。
3.11指令集概述
一个jvm指令由一个字节的操作码后跟0个或多个操作数构成。操作数的数目由操作码决定。
当操作数多于一个字节的时候,以高位字节在前的方式存储。
字节码指令流只是单字节对齐的(除了tableswitch,和lookupswitch的特殊指令对操作数的特殊要求),放弃了数据对齐,反映了对数据紧凑性的偏好,而排除了可能提高jvm仿真器性能的某些实现技术。
jvm指令中绝大多数是类型相关的,也就是作用于特定类型的操作数的。并在该指令的助记符中显示的标识出来。
具体的指令集后面细说。
3.12公共设计、私有实现
公共概念:class文件格式和jvm指令集