logo头像
ICQL

jvm_字节码

字节码

java程序 -> javac编译器 -> 字节码(.class) -> java虚拟机(win/linux/…)

Write Once, Run Anywhere “一次编译,到处运行”

编译后生成的字节码是一个中间语言
而程序最后运行是以 机器码 来执行的
java虚拟机就是用来将 字节码 在运行时转化为 机器码

class字节码数据的结构

8字节为基础单位的二进制数据,整个结构用 无符号数 2种数据结构来描述,多个字节的数据结构采用大端存储

无符号数: 基本数据类型,以u1,u2,u3,u4代表1,2,3,4个字节。
表: 是由多个无符号数或者其他表构成的复合数据类型(整个class字节码数据本质就是一张表)

大端小端:
数据存储以 8 bit (位)为一个 byte (字节),比如 0xab 就是一个字节
存储的内容长度很可能不止 8 位,比如 java 中 int 类型占 4 个字节 32 位

例如 0xabcd ,需要保存在4个字节里边,完整的是 0x0000abcd
0x0000abcd = 0xab * 0x100 + 0xcd
高位 -> 低位:00 -> 00 -> ab -> cd

大端(big-endian) 是高位的放在内存低地址处,低位的放在高地址处
小端(little-endian) 是高位的放在内存高地址处,低位的放在低地址处

假如 0xabcd 保存的地址是 0x100 - 0x103
大端:00(0x100)-> 00(0x101)-> ab(0x102)-> cd(0x103)
小端:cd(0x100)-> ab(0x101)-> 00(0x102)-> 00(0x103)

字节码数据结构

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
类型 名称 数量 说明
u4 magic(魔数) 1 确定是否是虚拟机可以接受的class文件,值为0xCAFEBABE,用以作为身份识别,类似于图片的字节用来标识是gif或者jpeg类型等
u2 minor_version(次版本号) 1 java次版本号(Minor Version)
u2 major_version(主版本号) 1 java主版本号(Major Version),jdk1.1是45.0,每个jdk大版本会在主版本号+1,jdk1.8是52(0x34),jvm根据主版本号和次版本号来确定是否可以加载class文件,jvm只能向下兼容
u2 constant_pool_count(常量个数) 1 常量池中数据的个数,计数是从1开始,例如值是(0x26=38),代表有38-1=37项常量,索引值就是1-37,特意将0空出来,是为了某些时候需要表达的不引用任何一个常量池项目,注意:除了常量池计数从1开始,其余计数都是从0开始
cp_info constant_pool(常量池表) constant_pool_count
u2 access_flags(类的访问控制权限) 1
u2 this_class(类名) 1
u2 super_class(父类名) 1
u2 interfaces_count(接口个数) 1
u2 interfaces(接口名) interfaces_count
u2 fields_count(字段个数) 1
field_info fields(字段表) fields_count
u2 methods_count(方法个数) 1
method_info methods(方法表) methods_count
u2 attributes_count(附加属性个数) 1
attribute_info attributes(附加属性表) attributes_count
  • 可使用javap –verbose class文件查看具体信息,或者使用16进制编辑器打开class文件查看
  • 内容:(有顺序)
    • 1、magic魔数:类型u4,数量1,确定是否是虚拟机可以接受的class文件,值为0xCAFEBABE,用以作为身份识别,类似于图片的字节用来标识是gif或者jpeg类型等。
    • 2、minor_version次版本号:类型u2,数量1,class文件次版本号
    • 3、major_version主版本号:类型u2,数量1,class文件主版本号,jdk1.1是45.0,每个jdk大版本会在主版本号+1,jdk1.8是52(0x34),jvm根据主版本号和次版本号来确定是否可以加载class文件,jvm只能向下兼容。
    • 4、constant_pool_count常量池数量:类型u2,数量1,
      引用常量池中数据的个数,计数是从1开始,例如值是(0x26=38),代表有38-1=37项常量,索引值就是1-37,特意将0空出来,是为了某些时候需要表达的不引用任何一个常量池项目,注意:除了常量池计数从1开始,其余计数都是从0开始。
    • 5、constant_pool常量池:class文件的资源仓库,大致分为2大类
      • 字面量(Literal):方法或字段中字符串String类型的值(特殊,实际值指向CONSTANT_Utf8_info),字段中基本类型的值(如果有赋值),各种类型的名字,变量名字(存在类型为CONSTANT_Utf8_info[tag:u1:1个,length:u2:1个,bytes:u1:length个]中,所以这些名字的数据量限制:保存数据的字节数组最大长度u2,2个字节,2^(82)=65536个,最大数据量为 2^(82)/1024=64kb)等。
      • 符号引用(Symbolic References):类型的全限定名,字段或方法的名称和描述符,方法句柄、类型,动态方法调用点等。
    • 6、access_flags访问标志:类型u2,数量1,是否public、abstract、final、interface、enum、annotation等等
    • 7、this_class类索引:类型u2,数量1,指向常量池的类符号引用
    • 8、super_class父类索引:类型u2,数量1,指向常量池的类符号引用
    • 9、interface_count接口索引计数器:初始值0
    • 10、interfaces接口索引集合:,指向常量池的类符号引用
    • 11、fields_count字段计数器:初始值0
    • 12、fields字段表集合:每个字段都有一个字段表,字段表的前几项用来描述字段,携带的属性表attributes_count,attributes用来存储其他信息
    • 13、methods_count方法计数器:初始值0
    • 14、methods方法表:每个方法都有一个方法表,方法表的前几项用来描述方法,携带的属性表attributes_count,attributes用来存储一些其他信息(其中Code属性:存储方法的字节码指令,抽象方法和接口方法没有此属性)
    • 15、attributes_count属性计数器:初始值0
    • 16、attributes属性表集合:class文件的属性表
微信打赏

赞赏是不耍流氓的鼓励