欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > JVM字节码文件结构深度剖析

JVM字节码文件结构深度剖析

2025/6/21 23:41:34 来源:https://blog.csdn.net/weixin_58611042/article/details/148778621  浏览:    关键词:JVM字节码文件结构深度剖析

反汇编,以下命令可以查看相对可读的详细结构

javap -verbose ByteCode.class

与Class二进制文件并不是直接对齐的

Class二进制文件结构参照表

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];附加属性表
}

在这里插入图片描述

常量池入口,占用二个字节,常量池中的第0个位置被我们的jvm占用了表示为null 所以我们通过编译出来的常量池索引是从1开始的。

常量池是 class 文件中一个用于存放各种**字面量(如字符串、数值)和符号引用(类名、字段、方法名等)**的表。

常量池常量结构表

u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数

tag均是u1

tag常量类型名称结构说明示例
1CONSTANT_Utf8UTF-8 编码字符串u2 length + u1[length] bytes:MUTF-8 编码的字符串“Hello”, “main”, “(I)V”
3CONSTANT_Integer整型常量u4 bytes:32 位整型值100-1
4CONSTANT_Float浮点型常量u4 bytes:IEEE 754 float3.14f
5CONSTANT_Long长整型常量u4 high_bytes + u4 low_bytes(注意占用两项)123456789012345L
6CONSTANT_Double双精度浮点常量u4 high_bytes + u4 low_bytes(注意占用两项)3.1415926535
7CONSTANT_Class类或接口名u2 name_index:指向一个 Utf8 常量java/lang/String
8CONSTANT_String字符串字面量引用u2 string_index:指向一个 Utf8 常量"Hello"
9CONSTANT_Fieldref字段引用u2 class_index + u2 name_and_type_indexSystem.out
10CONSTANT_Methodref方法引用u2 class_index + u2 name_and_type_indexprintln(String)
11CONSTANT_InterfaceMethodref接口方法引用u2 class_index + u2 name_and_type_indexComparable.compareTo(Object)
12CONSTANT_NameAndType名字和类型描述符组合,可以是字段名+类型,也可以是方法名+方法描述符u2 name_index + u2 descriptor_index<init>:()V, add:(II)I

13456属于字面量、其他属于符号引用类型

我们的常量池可以看作我们的java class类的一个资源仓库(比如Java类定的方法和变量信息),我们后面的方法类的信息的描述信息都是通过索引去常量池中获取。

  1. 常量池中主要存放二种常量,一种是字面量 一种是符号引用
    在这里插入图片描述
    在这里插入图片描述

在JVM规范中,每个字段或者变量都有描述信息,描述信息的主要作用是数据类型,方法参数列表,返回值类型等。 基本参数类型和void类型都是用一个大写的字符来表示,对象类型是通过一个大写L加全类名表示,这么做的好处就是在保证jvm能读懂class文件的情况下尽量的压缩class文件体积.

  1. 基本数据类型表示:
  • B---->byte
  • C---->char
  • D---->double
  • F----->float
  • I------>int
  • J------>long
  • S------>short
  • Z------>boolean
  • V------->void
  1. 对象类型:
  • String------>Ljava/lang/String;(前面有个L后面有一个分号)
  1. 对于数组类型: 每一个唯独都是用一个前置[来表示比如:
  • int[] ------>[I
  • String [][]------>[[Ljava.lang.String;

用描述符来描述方法的,先参数列表,后返回值的格式,参数列表按照严格的顺序放在()中
比如String getUserInfoByIdAndName(int id,String name) 的方法描述符号

  • (I,Ljava/lang/String;)Ljava/lang/String;

Class文件结构类的访问标识符号解析 Access_flag

标志位(hex)标志名含义
0x0001ACC_PUBLIC类是 public
0x0010ACC_FINAL类是 final(不可继承)
0x0020ACC_SUPER使用了新的 invokespecial 语义(Java 1.0.2+)
0x0200ACC_INTERFACE是接口
0x0400ACC_ABSTRACT是抽象类
0x1000ACC_SYNTHETIC编译器生成的类
0x2000ACC_ANNOTATION是注解(Annotation)
0x4000ACC_ENUM是枚举类

jvm规范并没有穷举出所以的类型 而是通过位运算的出来的。
0x0021 = 0x0020 位运算 0x0001 那么我们可以得出这个class的访问权限是ACC_PUBLIC 和ACC_SUPER

This class name的描述当前的所属类

this class name 占用二个字节,表示索引

super class name (当前class的父类名字)

同样占用二个字节,也是表示索引值

接口信息

实现的接口数量

占用二个字节表示实现了几个接口,是实现接口数量的上限也是0xffff

实现的接口

每个接口名占两个字节,来表示接口的位于常量池中的索引

字段表信息分析

字段结构

field_info {u2 access_flags;         // 访问标志(如 public、static、final 等)u2 name_index;           // 字段名称(指向常量池的 Utf8 项)u2 descriptor_index;     // 字段类型描述符(指向常量池的 Utf8 项)u2 attributes_count;     // 属性数量attribute_info attributes[attributes_count]; // 属性表(如 ConstantValue 等)
}

field_info.attributes一般会存:

  • ConstantValue
    只有 static final 常量字段才有,存储该字段的常量值(比如 public static final int MAX = 100;),内容是一个指向常量池中具体常量的索引。
  • Deprecated
    标记字段已经废弃,提示编译器或工具警告。
  • Synthetic
    标记字段是编译器生成的,不是源代码写的。
  • RuntimeVisibleAnnotationsRuntimeInvisibleAnnotations
    存储字段上的注解信息。

字段访问标志

标志位(hex)标志名含义
0x0001ACC_PUBLIC字段是 public
0x0002ACC_PRIVATE字段是 private
0x0004ACC_PROTECTED字段是 protected
0x0008ACC_STATIC字段是 static
0x0010ACC_FINAL字段是 final
0x0040ACC_VOLATILE字段是 volatile
0x0080ACC_TRANSIENT字段是 transient
0x1000ACC_SYNTHETIC编译器生成的字段
0x4000ACC_ENUM枚举类型字段

方法表信息分析

方法结构

method_info {u2 access_flags;           // 访问标志(public、static、final等)u2 name_index;             // 方法名索引(指向常量池)u2 descriptor_index;       // 方法描述符索引(参数类型和返回值)(()V 表示的是无参无返)u2 attributes_count;       // 属性个数attribute_info attributes[attributes_count]; // 属性数组(如Code属性)
}

method_info.attributes一般会存:

属性名说明
Code最核心: 存放方法的字节码指令、栈帧信息等(非 abstract/native 方法必须有)
Exceptions声明该方法可能抛出的异常列表(即 throws
LineNumberTable源代码行号到字节码地址的映射(调试用)
LocalVariableTable局部变量名、类型、作用域(调试用)
RuntimeVisibleAnnotations运行时可见注解
RuntimeInvisibleAnnotations编译期注解,运行时不可见
Synthetic标记该方法是编译器生成的,不是源代码写的
Deprecated标记该方法已过时
Signature泛型信息描述(如果用了泛型)
MethodParameters记录参数名(从Java 8开始)

方法访问标志

标志位(hex)标志名含义
0x0001ACC_PUBLIC方法是 public
0x0002ACC_PRIVATE方法是 private
0x0004ACC_PROTECTED方法是 protected
0x0008ACC_STATIC方法是 static
0x0010ACC_FINAL方法是 final
0x0020ACC_SYNCHRONIZED方法是 synchronized
0x0040ACC_BRIDGE编译器生成的桥接方法
0x0080ACC_VARARGS方法使用可变参数
0x0100ACC_NATIVE方法是本地方法(native)
0x0400ACC_ABSTRACT抽象方法
0x0800ACC_STRICT使用严格浮点数计算
0x1000ACC_SYNTHETIC编译器生成的方法

attribute_info

attribute_info {u2 attribute_name_index;//attribute名称常量池索引u4 attribute_length;//info长度u1 info[attribute_length];//具体数据
}
  • 类级别属性(ClassFile 末尾的 attributes[])
    • SourceFile_index
              SourceFile_attribute {u2 attribute_name_index;   // 常量池中 "SourceFile" 字符串的索引u4 attribute_length;       // 属性长度,固定为2u2 sourcefile_index;       // 指向常量池中一个 Utf8 字符串,表示源文件名(如 "Test.java")}
      
  • 字段级别属性(field_info 中的 attributes[])
    • ConstantValue
      用于修饰 静态字段(static final),表示该字段的编译时常量值,比如基本类型的字面量(int、long、float、double、String)。JVM 加载类时,会将这个值赋给对应的静态变量。
          ConstantValue_attribute {u2 attribute_name_index;    // 指向常量池中 "ConstantValue" 的 Utf8u4 attribute_length;        // 固定为 2u2 constantvalue_index;     // 指向常量池中该字段的常量值(Integer、Float、Long、Double、String)}
      
  • 方法级别属性(method_info 中的 attributes[])
    • code

      Code_attribute {u2 attribute_name_index;     // 必然指向 "Code"u4 attribute_length;         // 属性总长度(不含前6字节)u2 max_stack;                // 操作数栈最大深度u2 max_locals;              // 局部变量槽个数u4 code_length;              // 字节码长度(表示这个code[] 数组的字节数)u1 code[code_length];        // 字节码指令序列u2 exception_table_length;   // 异常处理表长度{u2 start_pc;u2 end_pc;u2 handler_pc;u2 catch_type; // 指向常量池(异常类),0代表 catch all} exception_table[exception_table_length];u2 attributes_count;//属性表的个数attribute_info attributes[attributes_count]; // Code 的子属性,比如 LineNumberTable 等
      }
      

      code[length]中存的是字节码指令助记符号(JVM执行的机器码)

    • LineNumberTable
      主要作用是 记录字节码指令与源代码行号的对应关系。便调试器定位当前执行的代码行,实现断点、单步调试等功能。

          LineNumberTable_attribute {u2 attribute_name_index;       // 常量池中 "LineNumberTable" 的索引u4 attribute_length;           // 属性长度u2 line_number_table_length;   // 表项个数(有些人对这个属性名定义不同,但是是同一个东西){u2 start_pc;               // 字节码偏移量(指令起始位置)u2 line_number;            // 源代码行号} line_number_table[line_number_table_length];}
      

      line_number_table_length+line_number_table[line_number_table_length]=info[attribute_length]

    • LocalVariableTable

          LocalVariableTable_attribute {u2 attribute_name_index;       // 常量池中 "LocalVariableTable" 字符串的索引u4 attribute_length;           // 属性长度u2 local_variable_table_length; // 局部变量表项数{u2 start_pc;               // 变量作用域开始的字节码偏移(相当于哪个字节码指令开始可以使用这个变量)u2 length;                 // 作用域长度(字节码偏移范围)u2 name_index;             // 变量名,指向常量池Utf8u2 descriptor_index;       // 变量类型描述符,指向常量池Utf8u2 index;                  // 局部变量表槽号} local_variable_table[local_variable_table_length];}
      

      local_variable_table_length+local_variable_table[local_variable_table_length]=info[attribute_length]

    • MethodParameters
      编译器(JDK 8+)如果开启 -parameters 参数,会在字节码里生成这个属性,保留方法参数名。反射时调用 Method.getParameters() 可以获得真实的参数名。

          MethodParameters_attribute {u2 attribute_name_index;u4 attribute_length;u1 parameters_count;{u2 name_index;     // 参数名(常量池Utf8索引)u2 access_flags;   // 参数修饰符,如 final, synthetic, mandated} parameters[parameters_count];}
      

      parameters_count+parameters[parameters_count=info[attribute_length]

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词