深入理解JVM4-Class文件结构

Class文件结构:平台无关,语言无关

jdk/bin目录下的javap命令可以输出class文件的字节码内容

class文件以字节为单位的二进制流,中间没有分隔符。字节序为Big-Endian(高位在前).

class文件中只有两种数据类型:无符号数,表。

表是由多个无符号数或其他表作为数据项构成的复合数据类型。表习惯性以“_info"结尾。

无论是符号数还是表,当同一类型但数量不定的多个数据时,使用一个前置的容量计数器加若干个连续的数据项的形式,称这些连续的某一类型的数据为某一类型的集合。常量池容量计算器从1开始(第0项常量空出来在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的情况),其余计算器从0开始。

每个class文件头4个字节被称为魔数(Magic number),确定这个文件是否为一个能被虚拟机接受的class文件。

4个字节版本号

Class文件格式

类型 名称 数量 含义
u4 magic 1 确定这个文件是否为一个能被虚拟机接受的class文件,固定的一个值
u2 minor version 1 次版本号
u2 major version 1 主版本号
u2 constant_pool_count 1 常量池中每个常量都是一个表,表的第一位是一个u1类型(1个字节)的标志位,描述符描述字段的数据类型、方法的参数列表和返回值
cp_info constant_pool constant_pool_count - 1 常量池中主要存放两类常量:字面量(文本字符串,声名为final的常量值等)和符号引用(类和接口的全限定名,字段的名称和描述符,方法的名称和描述符)
u2 access_flags 1 访问标志,识别类或接口的访问信息,(16个标志位,或的结果)
u2 this_class 1 类索引用于确定这个类的全限定名
u2 super_class 1 父类索引用于确定这个类的父类的全限定名
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1 字段表用于描述接口或类中声名的变量(包括类级变量(static)以及实例级变量)。
filed_info fields fields_count 字段修饰符用标志位表示,字段名和字段类型只能引用常量池中的常量描述。不会列出从超类或父接口中继承而来的字段。
u2 methods_count 1 方法中的Java代码经过编译成字节码后,存放在方法属性表集合中一个名为“Code”的属性中。
method_info methods methods_count 若方法没有被重写,就不会出现来自父类的方法信息。
u2 attributes_count 1
attribute_info attributes attributes_count Signature属性记录泛型签名信息(Java反射的API可以获取泛型类型),Code属性中存储方法的字节码指令,JVM规定一个方法不能超过2^16-1条字节码指令。Java编译器使用异常表而不是简单的跳转指令来实现异常及finally处理机制。

虚拟机拒绝执行超过其版本号的class文件。

Java虚拟机采用面向操作数栈而不是寄存器的架构。

方法的局部变量表和操作数栈所需容量大小在编译时确定,存储在方法的Code属性中。

方法若有异常时,code属性中字节码后面是异常表(catch子句中的异常),方法的attributes中可能有Exceptions属性,记录方法中可能抛出的受查异常(throws关键字后面列举的异常)。

JVM要求浮点数采用最接近数舎入模式。

long类型比较时,有符号数比较;浮点数比较时(dcmpg,dcmpl,fcmpg,fcmpl),无符号比较。

JVM在处理浮点数运算时,不会抛出任何运行时异常。

JVM支持方法级的同步和方法内部一段指令序列的同步,这两种都是用管程(Monitor)来支持的。

  1. 同步方法:无需通过字节码指令来控制,实现在方法调用和返回操作,同步方法将方法表中的方法的方法标志声名为同步方法。执行线程要先成功持有管程。
  2. 同步代码块:由monitorenter,monitorexit两条指令来支持。

Java 程序最初是通过解释器( Interpreter )进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为“热点代码”。为了提高热点代码的执行效率,在运行时,即时编译器(Just In Time Compiler )会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化。

热点代码分两类:

  • 被多次调用的方法
  • 被多次执行的循环体

JIT及时编译:将字节码在加载或执行时翻译成宿主机CPU的本地指令集。

  • IT编译启用时(默认是启用的),JVM读入.class文件解释后,将其发给JIT编译器。JIT编译器将字节码编译成本机机器代码。
  • 通常javac将程序源码编译,转换成java字节码,JVM通过解释字节码将其翻译成相应的机器指令,逐条读入,逐条解释翻译。

你可能感兴趣的:(JVM)