【JVM】一文读懂类的加载阶段

什么是类加载机制

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类的加载和连接过程都是在程序运行期间完成的,这样在类加载时会增加一些性能开销,但是提高了Java应用程序的灵活性。

类的生命周期

整个生命周期包括加载、验证、准备、解析、初始化、使用和卸载七个阶段,其中验证,准备,解析统称为连接。其中加载、验证、准备、初始化和卸载五个过程顺序是固定的,解析某些情况下可以在初始化之后。

加载

是将类的字节码载入到方法区中,如果这个类还有父类没有加载,先要加载父类,加载和连接可能是交替进行的。加载阶段虚拟机完成下面三件事情:

  1. 通过一个类的权限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。

验证

验证字节码的格式是否正确,是否符合虚拟机的要求,并且不会危害虚拟机安全。

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

准备

准备阶段是正式为静态变量分配内存空间并设置默认值的阶段,这些内存在JDK1.6之前将分配在方法区,现在分配在中。

静态变量分配空间和赋值时两个步骤,分配空间准备阶段完成,赋值初始化阶段完成。而final修饰的变量的赋值时发生在准备阶段。

解析

虚拟将常量池中的符号引用替换为直接引用。

符号引用:符号引用以一组符号来描述所引用的目标, 符号可以是任何形式的字面量, 只要使用时能够无歧义的定位到目标即可. 例如, 在Java中, 一个Java类将会编译成一个class文件. 在编译时, Java类并不知道所引用的类的实际地址, 因此只能使用符号引用来代替. 

直接引用就是引用的真实地址。

初始化

初始化即调用 <cinit>()v 方法,虚拟机会保证这个类的 “构造方法” 的线程安全。

会被初始化的情况:

  • main方法的所在类总是会被初始化
  • 首次访问这个类的静态变量或者静态方法时
  • 子类初始化时但是父类还没有初始化
  • 子类访问父类的静态变量,只会触发父类的初始化,子类不会初始化

不会被初始化的情况:

  • 访问类的 static final 静态常量不会触发初始化
  • 类对象 .class 不会触发初始化(加载阶段已经触发)
  •  创建该类的数组不会触发初始化
  • 类加载器的loadClass方法不会触发初始化(ClassLoader只会进行类的加载,不会解析和初始化)

类加载器

绝大多数Java程序都会使用到一下四种系统提供的类加载器:

  • 启动类加载器
  • 扩展类加载器
  • 应用程序类加载器
  • 自定义类加载器

启动类加载器

启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必由于虚拟机是按照文件名识别加载jar包的,如rt.jar,如果文件名不被虚拟机识别,即使把jar包丢到lib目录下也是没有作用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。

扩展类加载器

它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库。由Java语言实现,父类加载器为null。

应用程序类加载器

又称系统类加载器。它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。

双亲委派机制

类加载器双亲委派模型

双亲翻译为上级更容易理解,双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码。

如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成。

双亲委派模式的优点:

Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程芝士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值