jvm 官网字节码规范理解总结
Class文件结构
文件格式说明
- 类和接口的任何有效的表现形式都可以成为class文件格式 ,不必要拘泥于具体的文件 ,如网络字节或者classload生成的
- 每个class文件都是单个的一个类或则接口
- class文件是8位字节流构成的文件 ,大端形式,字节为最小单位 ,class文件也可以称为字节码文件(另外,Java和所有的网络通讯UDP/TCP/IP协议都是使用Big-Endian的编码
- 为了帮助理解 逻辑上定义u1 u2 u4 无符号数分别表示 124个字节来解释class文件
- 结构组成:无符号数(u1 u2 u4)和表两种数据类型 表由基本数据类型和其他表构成 定义的表一般由_info结尾
class文件解析
红框内为类型 右侧为具体的构成项名称 类型确定且顺序固定
magic :
- 确定jvm可接受的class字节流 0xCAFEBABE
- class文件不是已经表明了是class字节流嘛?因为文件后缀可变 且获取直接流不一定从文件中曲还可能网络等
minor_version/major_version
大小版本号
确定可以最低兼容的jvm版本号 比如0X32 =50 java版本号从45(1.1)开始 50即1.6版本 可由1.6以上jvm执行
constant_pool_count/constant_pool重点常量池
- 先由constant_pool_count 确定常量池数量 确定常量池字节流读到哪结束‘ 数量大与常量池数量1个 第0为用于表达不想引用常量池的项目
- 常量池是个表:1、两大常量 字面量(所见即所得的语言层面的常量)和符号引用(使用字面量组成的引用)
2、具体类型 每个常量类型都有自己的结构 单都有一个功能的tag标志用来确定是那种类型
CONSTANT_..._info {
u1 tag;
....
}
access_flags
类访问标识
this_class/supper_class/interfaces
- 类索引/父类索引/接口索引集合 :这三个按顺序访问确定类继承关系
- 类索引和父类索引都指向常量池CONSTANT_Class_info常量
field_info/method_info
字段表包含本类或接口所有实例或类变量 不包括父类 编译器有可能自己添加
所有的变量都用field_info描述
方法表大致相似
方法表的代码
field_info {
u2 access_flags; 访问权限
u2 name_index; 名称常量池索引
u2 descriptor_index;描述符索引
u2 attributes_count;
attribute_info attributes[attributes_count];
}
描述符是额外的一些信息 如变量是常量 static a = “123”的话 会有一个constantvalue描述类型指向常量“123” 对于方法表会有一些返回值 参数值等描述
attribute_info
属性表
- 允许编译器class在文件结构attributes表中定义和发出包含新属性 的class文件。允许Java虚拟机实现识别和使用在文件结构attributes表中找到的新属性 class。但是,任何未定义为该Java虚拟机规范一部分的属性都不得影响类或接口类型的语义。Java虚拟机实现需要静默忽略它们无法识别的属性
2编译后的代码存在code属性中
Java虚拟机代码的约束
方法,实例初始化方法或类或接口初始化方法的Java虚拟机代码存储在文件结构code的Code属性的数组中
分静态约束和结构约束
格式检查
当Java虚拟机class 加载了预期文件时,Java虚拟机首先确保该文件具有文件的基本格式class。此过程称为格式检查。前四个字节必须包含正确的幻数。所有公认的属性必须具有适当的长度。该class文件不得被截断或末尾有多余的字节。常量池不得包含任何表面上无法识别的信息。
对于文件内容的class 任何解释,都必须进行基本文件完整性检查class。
格式检查不同于字节码验证。两者都是验证过程的一部分。从历史上看,格式检查一直与字节码验证相混淆,因为两者都是完整性检查的一种形式。
验证class文件
即使使用Java编程语言的编译器只能生成class满足前面部分中所有静态和结构性约束的文件,但Java虚拟机也不保证要求其加载的任何文件是由该编译器生成的或格式正确的。诸如Web浏览器之类的应用程序不下载源代码,而是将其编译。这些应用程序下载已编译的class文件。浏览器需要确定class文件是由值得信赖的编译器还是由尝试利用Java虚拟机的对手生产的。
Java虚拟机实现class在链接时验证每个文件是否满足必要的约束
链接时验证可提高解释器的性能。可以省去昂贵的检查,否则将不得不在运行时为每个解释的指令执行验证约束。Java虚拟机可以假定已经执行了这些检查。例如,Java虚拟机将已经知道以下内容:
- 没有操作数堆栈上溢或下溢。
- 所有局部变量的使用和存储均有效。
- 所有Java虚拟机指令的参数均为有效类型。
验证者还可以执行验证,而无需查看属性code数组Code执行的检查包括以下内容:
- 确保final 类没有被子类化,并且final方法没有被重
- 检查每个类(除外Object)是否都有直接的超类。
- 确保常量池满足记录的静态约束;例如,CONSTANT_Class_info常量池中的每个结构在其name_index项中都包含该CONSTANT_Utf8_info结构的有效常量池索引。
- 检查常量池中的所有字段引用和方法引用都具有有效的名称,有效的类和有效的类型描述符。
Java虚拟机实现可以使用两种策略进行验证:
1 必须使用“通过类型检查进行验证”来验证class版本号大于或等于50.0的文件。
2 除符合Java ME CLDC和Java Card概要文件的实现外,所有Java虚拟机实现都必须支持按类型推断验证,以便验证class 版本号小于50.0的文件。
支持Java ME CLDC和Java Card概要文件的Java虚拟机实现的验证受它们各自的规范支配。
Java虚拟机的局限性
class文件格式隐含了Java虚拟机的以下限制:
每个类或每个接口的常量池被constant_pool_count该ClassFile结构的16位 限制为65535个条目
类或接口可以声明的字段数由结构fields_count 的大小限制为65535 fields_count项的值ClassFile不包括从超类或超接口继承的字段。
类或接口可以声明的方法的数量由结构methods_count项的大小限制为65535 methods_count项的值ClassFile不包括从超类或超接口继承的方法。
类或接口的直接超级接口的数量受结构interfaces_count项大小的限制ClassFile
。。。