美文网首页
JVM类加载机制解析之字节码

JVM类加载机制解析之字节码

作者: Pasonx | 来源:发表于2018-12-06 17:35 被阅读0次

今天我们来聊一聊Java虚拟机的类加载机制。首先要想了解Java虚拟机是如何加载一个类的,那么首先要对.class字节码文件的结构有一个相对深入的理解。

.class字节码文件的结构

.class文件是一组以8字节为一组(基础单位)的二进制字节流,中间没有任何分隔符。当遇到需要占用8位字节以上的数据项,会按照高位在前的方式分割成若干个8位字节进行存储,高位在前的数据存储顺序(Big-Endian)与x86处理器的(Little-Endian)对应。

.class文件采用类似C语言结构体的伪结构来存储数据,里面只有无符号数和表两种数据结构,解析都要以这两种类型为基础。无符号数属于基本的数据类型,以u1,u2, u4, u8来分别代表1, 2, 4, 8个字节的无符号数。无符号数可以用来表示数字, 索引引用,数量值或者按照UTF-8编码构成字符串值。

下面是一张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];
}

表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个class文件本质就是一张表。

下面我们先来看一段代码:

public class MyTest2 {
    String str = "Welcome";
    private int x = 5;
    public static Integer in = 10;

    public static void main(String[] args) {
        MyTest2 myTest2 = new MyTest2();
        myTest2.setX(8);
        in = 20;
    }

    public void setX(int x) {
        this.x = x;
    }
}

编译后对应生成的字节码文件格式如下:


字节码文件16进制形式

.class文件的头4个字节称为魔数,它的作用是确定这个文件是否为一个能被虚拟机接受的.class文件,这4个字节的内容为0xCAFEBABE, 接下来紧接着的四个字节是版本号。其中,第5-6字节存储的是次版本号,第7-8存储的是主版本号。再下来是常量池入口,它可以理解为.class文件的资源仓库。
通过javap -v MyTest2.class可以生成字节码相关的信息,我们将常量池部分截取展示如下:

Constant pool:
   #1 = Methodref          #10.#34        // java/lang/Object."<init>":()V
   #2 = String             #35            // Welcome
   #3 = Fieldref           #5.#36         // com/shengsiyuan/jvm/bytecode/MyTest2.str:Ljava/lang/String;
   #4 = Fieldref           #5.#37         // com/shengsiyuan/jvm/bytecode/MyTest2.x:I
   #5 = Class              #38            // com/shengsiyuan/jvm/bytecode/MyTest2
   #6 = Methodref          #5.#34         // com/shengsiyuan/jvm/bytecode/MyTest2."<init>":()V
   #7 = Methodref          #5.#39         // com/shengsiyuan/jvm/bytecode/MyTest2.setX:(I)V
   #8 = Methodref          #40.#41        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #9 = Fieldref           #5.#42         // com/shengsiyuan/jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
   #10 = Class              #43            // java/lang/Object
   #11 = Utf8               str
   #12 = Utf8               Ljava/lang/String;
   #13 = Utf8               x
   #14 = Utf8               I
   #15 = Utf8               in
   #16 = Utf8               Ljava/lang/Integer;
   #17 = Utf8               <init>
   #18 = Utf8               ()V
   #19 = Utf8               Code
   #20 = Utf8               LineNumberTable
   #21 = Utf8               LocalVariableTable
   #22 = Utf8               this
   #23 = Utf8               Lcom/shengsiyuan/jvm/bytecode/MyTest2;
   #24 = Utf8               main
   #25 = Utf8               ([Ljava/lang/String;)V
   #26 = Utf8               args
   #27 = Utf8               [Ljava/lang/String;
   #28 = Utf8               myTest2
   #29 = Utf8               setX
   #30 = Utf8               (I)V
   #31 = Utf8               <clinit>
   #32 = Utf8               SourceFile
   #33 = Utf8               MyTest2.java
   #34 = NameAndType        #17:#18        // "<init>":()V
   #35 = Utf8               Welcome
   #36 = NameAndType        #11:#12        // str:Ljava/lang/String;
   #37 = NameAndType        #13:#14        // x:I
   #38 = Utf8               com/shengsiyuan/jvm/bytecode/MyTest2
   #39 = NameAndType        #29:#30        // setX:(I)V
   #40 = Class              #44            // java/lang/Integer
   #41 = NameAndType        #45:#46        // valueOf:(I)Ljava/lang/Integer;
   #42 = NameAndType        #15:#16        // in:Ljava/lang/Integer;
   #43 = Utf8               java/lang/Object
   #44 = Utf8               java/lang/Integer
   #45 = Utf8               valueOf
   #46 = Utf8               (I)Ljava/lang/Integer;

常量池结构分析

既然常量池被称为是.class文件的资源仓库, 它自然是.class文件结构中与其他项目关联最多的数据类型,也是占用.class文件空间最大的数据项目之一。

由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置u2类型的constant_pool_count来计数常量池中的常量个数。但是仔细观察你会发现,在十六进制的表示中,第9-10个字节表示constant_pool_count, 即00 2F也就是2*16+15=47,但是在常量池中我们只看到了46个常量,这是为什么呢?其实,这是因为0这个位置用来表示常量池不引用任何常量的含义。

相关文章

  • JVM的类加载机制

    类加载机制 JVM把class(字节码)文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用...

  • Java并发底层实现原理

    Java代码在编译后变成字节码,字节码被类加载器加载到JVM,JVM解析执行字节码,转化为机器码在CPU上执行,J...

  • 12.反射

    Java类加载机制: JVM和类:运行Java: java 带有main方法的类名启动JVM,并加载字节码. ...

  • 类加载过程

    类加载机制 JVM把描述类的数据的字节码(.Class文件)加载到内存,并对数据进行校正、转换解析和初始化,最...

  • Java并发机制的底层实现原理

    Java并发机制的底层实现原理 Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执...

  • 类加载浅析

    类加载机制JVM把描述类的数据的字节码(.Class文件)加载到内存,并对数据进行校正、转换解析和初始化,最终形成...

  • Android类加载器以及与Java类加载器区别

    JVM之类加载机制Android类加载器 Android类加载器和Java类加载器比较 加载的字节码不同 相同的是...

  • JVM类加载机制解析之字节码

    今天我们来聊一聊Java虚拟机的类加载机制。首先要想了解Java虚拟机是如何加载一个类的,那么首先要对.class...

  • JVM知识精粹

    1.jvm执行字节码文件 流程:jvm通过类加载器加载字节码文件----字节码校验器---翻译字节码(解释执行,反...

  • JVM综述

    关键词:java字节码、java类加载机制、jvm内存模型、jvm垃圾回收机制 ZERO 持续更新 请关注:ht...

网友评论

      本文标题:JVM类加载机制解析之字节码

      本文链接:https://www.haomeiwen.com/subject/bapbcqtx.html