一、Class文件结构
Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件中,中间没有任何分隔符。根据《java虚拟机规范》的规定,class文件格式采用一种类似于C语言结构体的伪结构来存储数据。伪结构中只有两种数据类型:无符号数和表。
- 无符号数属于基本数据类型,以u1、u2、u4、u8来分别代表1、2、4、8个字节的无符号数。
- 表由多个无符号数或其他表作为数据项构成的复合数据类型。整个class文件本质上也可以视为一张表。
class文件具体内容包含魔数、版本号、常量池、访问标志、索引集合、字段表集合、方法表集合、属性表集合等数据。
魔数是class文件的头4个字节,它唯一的作用是确定这个文件是否是一个能够被虚拟机接受的class文件。class文件的魔数固定为0xCAFEBABE。
常量池相当于class文件的资源仓库,主要存放字面量和符号引用。
由于class文件中方法、字段等都需要引用CONSTANT_Utf8_info型常量来描述名称,所以CONSTANT_Utf8_info型常量的最大长度也就是Java中方法、字段名的最大长度,即u2类型最大值65535。所以Java中超过64KB英文字符的变量或方法名是无法编译的。
二、字节码指令
java虚拟机支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都使用管程(Monitor,即通常所说的“锁”)来实现。
方法级的同步是隐式的,不需要通过字节码指令控制,它实现在方法调用和返回操作之中。虚拟机可以从方法常量池中的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否被声明为同步方法。调用方法时,调用指令检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后方法完成时释放管程。如果方法执行时遇到异常,且在方法内部无法处理,那这个同步方法所持有的管程将在异常抛到同步方法边界之外时自动释放。
同步一段指令集序列由synchronized语句块表示,java虚拟机指令集中有monitorenter和monitorexit两条指令来支持synchronized关键字的语义。