JVM----Class类文件结构
JVM平台无关性
Java具有平台无关性,也就是任何操作系统都能运行Java代码。之所以能实现这一点,是因为Java运行在虚拟机之上,不同的操作系统都拥有各自的Java虚拟机,因此Java能实现“一次编写,处处运行”。而JVM不仅具有平台无关性,还具有语言无关性。 平台无关性是指不同操作系统都有各自的JVM,而语言无关性是指Java虚拟机能运行除Java以外的代码!这听起来非常惊人,但JVM对能运行的语言是有严格要求的。
首先来了解下Java代码的运行过程。Java源代码首先需要使用Javac编译器编译成class文件,然后启动JVM执行class文件,从而程序开始运行。 也就是JVM只认识class文件,它并不管何种语言生成了class文件,只要class文件符合JVM的规范就能运行。 因此目前已经有Scala、JRuby、Jython等语言能够在JVM上运行。它们有各自的语法规则,不过它们的编译器都能将各自的源码编译成符合JVM规范的class文件,从而能够借助JVM运行它们。
Class文件结构
1.魔数
Class文件是一组以8位字节为基础单位的二进制流,包含多个数据项目(数据项目的顺序,占用的字节数均由规范定义),各个数据项目严格按照顺序紧凑的排列在Class文件中,不包含任何分隔符,使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据,没有空隙。当遇到需要占用超过8位字节以上空间的数据项目时,会按照高位在前的方式分割为多个8位字节进行存储
数据项目分为2种基本数据类型(以及由这两种基本数据类型组成的集合):
1,无符号数,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数
2,表,以“_info”结尾,由多个无符号数或其它表构成的复合数据类型
Class文件格式如下表所示:
在上图中,在数量字段中,有些是1而有些则不是,不是1的代表的是相同类型的多个数据,将这一系列连续的数据成为称为某一个类型的集合。class文件的格式要求非常严格,这个字节代表什么,长度,先后顺序如何,都是死的,不能改变,比如如下代码:
public class TestClass { private int m; public int inc() {
return m + 1;
}
}
这个class文件的头四个字节为“CAFEBABE”,他的作用是确定该文件是否是一个能被jvm解析的class文件,被称为“魔数”。
紧接着魔数的四个字节存储的是Class文件的版本号,第五和第六是次版本号,第七和第八是主版本号,在上图中,该版本为50。
2.常量池
从class文件结构图中可以看到,紧接着魔数的是常量池入口,常量池可以被认为是Class文件中的资源仓库,它是class文件中与其他资源关联最多的数据类型,也是占用class空间最大的一个数据项,也是class文件中第一个出现的表类型的数据项。
由于常量的数目是不确定的,所以在常量池的入口放一个u2类型的数据“content_pool_count”,用来代表常量池容量计数器。注意:常量池的数目是从1开始的,不是从0。上面贴出的十六进制图中,偏移地址对应0x00000008,也就是0x0016,对应的十进制数是22,也就是说常量池为21个常量,1~21。为什么从1开始,而不是0,因为0代表的是该class文件的特殊情况:不引用任何一个常量。不过其他的类型集合,都是从0开始的!
常量池主要存放两大类常量:
(1)字面量:如文本字符串、final变量。
(2)符号引用:符号引用又分为三种
* 类和接口的全限定名
* 字段的名称及描述
* 方法名称及描述
Java代码编译完之后,class文件不会保存各个方法字段的最终内存信息,而是在运行期间,从常量池中获得对应的符号引用,在类创建时或者运行时解析,再翻译到具体的内存地址。
常量池中每一个常量都是一个表,这些常量都有一个特点,就是表的开始的第一位是u1类型的数据,它是一个标志位(tag),代表这个常量是哪种类型如图:
每种常量他们都是一张表,而这些表,他们每个结构都是不一样的。常量池入口后面的0x07就是一个标志位,代表的是CONSTANT_Class_info常量,之后的0x01代表的是CONSTANT_Utf-8_info,也就是该常量池的第二项常量。并且方法、字段等都需要引用CONSTANT_Utf-8_info来描述,所以CONSTANT_Utf-8_info的最大长度就是Java方法和字段的最大长度,因为u2类型的数据最大值为65535,所以方法和字段最大就是64KB,否则无法编译。
14种常量池的各自结构如下:
3.访问标志
常量池结束之后,紧着有俩字节代表的是访问标志,用于识别一些类或者接口层次的访问信息。包括,该class是类还是接口,是否为public,是否定义了abstract,如果是类的话,是否有final属性。
根据上面的表格,测试类的访问标志为ACC_PUBLIC | ACC_SUPER = 0x0001 | 0x0020 =1 | 32 = [00000000][00000001] | [00000000][00010000] = [00000000][00010001] = 33 = 0x0021
4.类索引、父类索引与接口索引集合
类索引、父类索引都是一个u2类型的数据,接口索引集合也是一个u2类型的数据,class文件通过这三个数据项来确定这个类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确定父类的全限定名。父类索引最多有两个(其中有一个是Object)。
类索引、父类索引、接口索引都在访问标志之后,引用CONSTANT_Class_info,再通过引用到CONSTANT_Utf-8_info,代表的是该类的全限定名的字符串。对于接口索引集合,入口的第一项就是u2类型的计数器,表示的是索引的接口的数目,如果没有实现接口,就是0。
5.字段表集合
字段表负责描述接口或类中的声明的变量,该字段包括了类变量和实例变量,但是不包括局部变量。一个字段可以包含的信息:字段的访问权限,字段的修饰符,字段的名称,字段所属的类型。字段的类型、字段名字,这些都是无法固定的,所以通过符号引用来标识。
如下图所示的是字段表,第一个是access_flags,这个和类索引里的是一样的,name_index和descriptor_index,name_index代表的是一个字段的简单名称,例如上面代码里的m,简单名称就是m。
descriptor_index代表的是描述符,字段和方法的描述符就是指字段的数据类型、方法参数列表、返回值。描述符标识符含义如图所示:
这个是name_index对应的是字段的简单名称
这个是descriptor_index对应的是字段的描述符
通过上面的分析,我们可以得出该字段的是:int m。
字段表的固定数据(访问标志、简单名称、类型)到这里就结束了,descriptor_index后面还存储着一些其他的信息,这些属于描述字段的额外信息,如果是
static final int m=1;那么就还存在一个ConstantValue的属性,指向常量1。
6.方法表集合
方法表集合和之前的字段表集合有很多相似之处,方法表结构和字段表集合一样,也是开头就是access_flags(描述该方法的一些访问标识),之后就是name_index(方法的简单名称),descriptor_index(方法的描述符:方法参数列表、返回值),属性表集合。
第一个方法(由编译器自动添加的默认构造方法):
access_flags为0x0001,即public;name_index为0x0007,即常量池中第7个常量;descriptor_index为0x0008,即常量池中第8个常量
const #7 = Asciz <init>;
const #8 = Asciz ()V;
第一个方法是init(name_index对应的是7),而描述符就是()V(descriptor_index对应的是8)
7.属性表集合
属性表在前面已经出现了多次,包括字段表集合、方法表集合,属性表可以用来描述某些特殊场合下的专有信息。与Class文件中其它数据项对长度、顺序、格式的严格要求不同,属性表集合不要求其中包含的属性表具有严格的顺序,并且只要属性的名称不与已有的属性名称重复,任何人实现的编译器可以向属性表中写入自己定义的属性信息。虚拟机在运行时会忽略不能识别的属性,为了能正确解析Class文件,虚拟机规范中预定义了虚拟机实现必须能够识别的9项属性:
Code属性:Java程序方法体中的代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性中。当然不是所有的方法都必须有这个属性(接口中的方法或抽象方法就不存在Code属性),Code属性表结构如下:
max_stack:操作数栈深度最大值,在方法执行的任何时刻,操作数栈深度都不会超过这个值。虚拟机运行时根据这个值来分配栈帧的操作数栈深度。
max_locals:局部变量表所需存储空间,单位为Slot(参见备注四)。并不是所有局部变量占用的Slot之和,当一个局部变量的生命周期结束后,其所占用的Slot将分配给其它依然存活的局部变量使用,按此方式计算出方法运行时局部变量表所需的存储空间。
code_length和code:用来存放Java源程序编译后生成的字节码指令。code_length代表字节码长度,code是用于存储字节码指令的一系列字节流。
每一个指令是一个u1类型的单字节,当虚拟机读到code中的一个字节码(一个字节能表示256种指令,Java虚拟机规范定义了其中约200个编码对应的指令),就可以判断出该字节码代表的指令,指令后面是否带有参数,参数该如何解释,虽然code_length占4个字节,但是Java虚拟机规范中限制一个方法不能超过65535条字节码指令,如果超过,Javac将拒绝编译。
JVM----Class类文件结构的更多相关文章
- 深入理解JVM(六)类文件结构
6.1 关于类文件 1.class文件的一次编译,到处运行的跨平台性: 2.JVM不止有跨平台性,还有跨语言性,不管是JRuby还是Groovy写出来的程序,只要编译出符合JVM规范的class文件就 ...
- JVM(4) 类文件结构
一.实现“平台无关性” 字节码(ByteCode)存储格式和虚拟机是实现语言无关性的基础.Java虚拟机不和包括Java在内的任何语言绑定,它只与“Clas”文件这种特定的二进制文件格式所关联,Cla ...
- JVM小结--类文件结构
字节码是构成Java平台无关性的基石.实现语言无关性的基础是虚拟机和字节码存储格式. Java语言中的各种变量.关键字和运算符的语义最终是由多条字节码命令组成,因此字节码命令所能提供的语义描述能力肯定 ...
- JVM学习笔记(三):类文件结构
代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 实现语言无关性的基础是虚拟机和字节码存储格式.Java虚拟机不和包括Java在内的任何语言绑定,只与&quo ...
- jvm 类文件结构学习
本文以代码示例来学习 java 类文件的结构,其中对类文件结构的学习均来自周志明先生所著的 <深入理解 Java 虚拟机>一书,在此表示诚挚的感谢. 代码如下: package com.r ...
- 【搞定Jvm面试】 面试官:谈谈 JVM 类文件结构的认识
类文件结构 一 概述 在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机.Java 语言通过字节码的方式,在一定程度上解决 ...
- 四、JVM — 类文件结构
类文件结构 一 概述 二 Class 文件结构总结 2.1 魔数 2.2 Class 文件版本 2.3 常量池 2.4 访问标志 2.5 当前类索引,父类索引与接口索引集合 2.6 字段表集合 2.7 ...
- jvm(4):类文件结构
typora-root-url: ./ 类文件结构 魔数Magic Number 每个Class文件的头4个字节是魔数.值为0xCAFEBABE 唯一作用:确定这个文件是一个能被虚拟机接受的Class ...
- JVM类文件结构
作为一名Java后台开发的程序员, 深入理解JVM, 重要性不言而喻, 这篇文章主要是记录JVM类文件结构相关知识. 2. 实例 这部分比较抽象, 所以以实例的形式来学习. 这部分作为资料, 以便后面 ...
- JVM学习第三天(JVM的执行子系统)之开篇Class类文件结构
虽然这几天 很忙,但是学习是不能落下的,也不能推迟,因为如果推迟了一次,那么就会有无数次;加油,come on! Java跨平台的基础: 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节 ...
随机推荐
- Jboss未授权访问部署木马 利用exp
查看系统名称 java -jar jboss_exploit_fat.jar -i http://www.any.com:8080/invoker/JMXInvokerServlet get jbos ...
- IDEA GIT 忽略文件
1.装插件 .igore 2.新建忽略文件格式 3.编辑忽略后缀文件 可以是文件夹 也可以是 具体文件类型
- Java和操作系统交互(Java 代码是怎么执行)(转)
结合 CPU 理解一行 Java 代码是怎么执行的 根据冯·诺依曼思想,计算机采用二进制作为数制基础,必须包含:运算器.控制器.存储设备,以及输入输出设备,如下图所示. 我们先来分析 CPU 的工作原 ...
- Flutter——Text组件(文字组件)
名称 功能 textAlign 文本对齐方式(center 居中,left 左 对齐,right 右对齐,justfy 两端对齐) textDirection 文本方向(ltr 从左至右,rtl 从右 ...
- 关于linux一些备份、还原,压缩,归档的命令
15.1 gzipgzip(1) 是GNU的压缩程序.它只对单个文件进行压缩.基本用法如下:$ gzip filename程序执行以后,文件名会变成filename.gz,而且一般情况下大小会比原文件 ...
- Paper Reading:Deep Neural Networks for Object Detection
发表时间:2013 发表作者:(Google)Szegedy C, Toshev A, Erhan D 发表刊物/会议:Advances in Neural Information Processin ...
- 二叉堆的应用——查找长度为N数组中第M大数
看到这个题目首先想到是排序,那么时间复杂度自然就是O(NlgN).那么使用二叉堆如何解决呢? 对于下面一个数组,共有12个元素,我们的目标就是找出第5大元素——12 首先建立一个具有M个元素的最小堆, ...
- Centos6.5 下安装配置Apache+PHP+Mysql环境
1.准备工作 # yum -y update && yum -y install vim make cmake gcc gcc-c++ bison bison-devel ncurse ...
- 获取DataFrame列名的3种方法
df= pd.DataFrame({'a': range(10, 20), 'b': range(20, 30)}) df 1.链表推倒式 [column for column in df][a,b] ...
- Qt 解释JSon数据
jsondata={"cmd":"meetingmemberlist","memberinfos":[{"name":& ...