微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JVM篇(六)--类加载过程

1.类加载执行过程

类加载子系统处于中间位置,它前面是一个字节码文件,有了字节码文件需要类加载子系统进行读取,对.class文件的规格进行检查判断,然后在将常量池也好,字段与发放的描述按照规则加载到JVM内存中存储,类加载子系统就相当于运行时数据区的入口所在

1.1 类加载子系统介绍

 1.类加载子系统负责从文件或者网络加载Class字节流,(类文件不一定都是在此磁盘的,只要符合这个字节流,通过网络或者其他介质都是可以加载的)

  2.类加载子系统会读取字节码中的信息,运行时存储到jvm中

  3.任何Class要被类加载子系统加载,都要符合JVM的规范

1.2 类加载执行过程

类先判断是否被加载过,没有的话去加载类到jvm的内存中存储,在内存中就拥有了字节码的信息,但是还没有生效,因为还没有验证需要进入第二阶段。

链接阶段:又分为验证、准备、解析

验证阶段就是将刚存储的字节码信息按jvm的规范进行校验,比如前4个字节是不是cafe xxxx ,后四个字节是不是版本号等等,验证都是在这个阶段完成的

准备阶段:就是将类的成员变量赋给认的值,比如 int 类型的就会赋值成0。

解析阶段:比较复杂,就是在字节码中的符号引用转换为内存中的直接引用。

最后阶段初始化:类变量静态代码块赋予真正的变量值

根据这三个类的初始化就完成了,后续就可以进行实际运行,根据初始化的类,程序就可以对对象进行实例化的工作,后面会分别讲解这几个过程

2.类加载阶段

类加载阶段主要的事情是 字节码文件的数据以二进制流的方式被jvm中的类加载器进行读取和加载,在这个过程中做了如下几件事情:

1.类加载器读取字节码二进制流(读文件)

2.解析字节码二进制流的静态数据转换为运行时JVM放法区数据。(方法区时很重要的区域,类、字段、方法,常量信息都在内存运行时存储到方法区中)

3.解析完成以后,生成类的java.lang.class,类对象会存放到堆中,作为方法区的访问入口。

4.在加载类的过程中,比如会触发父类加载(子类加载,父类也会按照上面1-3依次进行加载处理操作)

一个A.class字节码文件,类加载器会判断运行时数据区是否有A类呢?如果没有的话,类加载器进行读取A类字节码文件,读取的同时也会分析A类,发现A类文件是有继承关系的BaseA,那么类加载器就会先加载BaseA,这里有两个区域,BaseA与A都有对应的方法区存储的数据,以及字节对应对象的实例就是堆区,也就是说A类里的字节码文件的信息是放在方法区,通过A的class实例就可以获得对应类的字段和方法

一个Class字节码文件被类加载器加载,如果有父类先加载父类,在加载子类,会加载到堆区的对应实例作为入口,可以访问方法区中所对应的字段等等信息

Class何时被创建?

1.new实例化时: A a=new A();

2.反射:Class clza=Class.forName("xx.xx.A");

3.子类加载时父类同时加载

4.JVM启动时,包含main方法的主体会被加载,以及所有对象对的父类都时Object,所以程序启动前必有Object的类

5. 1.7动态类型语言支持

3.类链接(Linking)阶段

链接阶段有三个步骤:

1.验证(verify):确保字节码符合虚拟机要求

2.准备(prepare):为字段赋予初始值

3.解析(resolve):符号引用转为直接引用

2.1 验证阶段

验证阶段的内容基本就是以下图的内容

验证阶段和加载阶段是交替执行的,读取的二进制流就可以直接验证,这里的验证阶段不是对运行时环境加载内存的操作,只是对二进制操作,是否符合条件

1.文件格式校验:前4个字节是否时CAFEBABE,后面4个字节是否时版本号等等

2.元数据匹配语义分析:是否是正确能被使用的语义

3.字节码校验,数据流与控制流分析:平常接触的类型转换是否有校,返回值缺少,还是到哪里不需要返回值等等

4.符号引用:能否找到类、方法等信息

2.2 准备阶段

为static值赋值成初始值,不同类型赋予不同的值,图下的表格是不同的值的初始值,什么时候赋值成真正的值呢,那需要在初始化阶段,初始化阶段是类加载最后一个阶段

2.3 解析阶段

链接中的最后一个操作,将符号引用转换为直接引用,也就是上图中说明,

符号引用:静态字面  

直接引用:动态指针关联

对上面的图 A类,它的父类是BaseA类,符号引用就是用字符串字面的表达方式说明A与BaseA的关系,this class:A     superClass:BaseA,以这种方式说明他们的关系。

在程序运行中A与BaseA是一个实例,他们的关系需要动态的指针去关联,当然知道是什么关系是通过字符串字面去转换指针关联的

解析阶段对哪些事物进行解析呢?

  1. 类解析
  2. 字段解析
  3. 方法解析
  4. 接口解析

1.4 类初始化阶段

初始化阶段是对类的初始阶段对clint方法的执行。

 

1.初始化阶段就是对类变量以及静态变量进行初始化的。

2.子类初始化按照正常加载逻辑,子类创建对象当知道有父类的时候会优先加载父类,那么这里也是子类初始化会优先执行父类的初始化

3.没有类变量和静态代码就不会产生clint(初始化)

4.jvm启动可以选择加+TraceClassLoading来查看类加载顺序,帮助学习

5.为了只初始化依次,初始化方法会加同步锁

咱们用代码演示下:

ClassInitSamples是子类,继承Base类

ClassInitSamples有两个静态类变量,还有一个静态代码块,代码块里的代码是对类变量赋值操作。然后main方法new ClassInitSamples类

父类也有一个静态变量和静态代码块,

测试启动子类的main方法发现父类的初始化是需要先执行的。

如果此时你用JCLASSlIb查看字节码文件,能看到有Clint初始方法。当然此时把类变量和静态方法块去掉,你要是用JCLASSlIb就可以查看字节码里没有了clint了。

 

在vm加入此单词,运行就会把加载顺序过程展示出来

后面就不一一测试了,初始化的知识点概括在以下几点:

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐