JVM类加载过程详解 & 类加载器的两种架构模型:双亲委派模型和OSGi模块化模型

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

类加载的过程包括了加载、验证、准备、解析、初始化五个阶段 (验证、准备、解析合称连接阶段)

:加载-验证,准备-解析,初始化

加载

载入字节流

​ 加载时类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名来获取其定义的二进制字节流。

    注意,这里第1条中的二进制字节流并不只是单纯地从Class文件中获取,比如它还可以从Jar包中获取、从网络中获取(最典型的应用便是Applet)、由其他文件生成(JSP应用)等。

  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

  3. 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。

  4. 类加载器就是进行这阶段的工作 – java把这一部分作为外置代码,可自定义类加载器,可以从各种源获取代码,灵活性大大提升

验证

格式 + 安全

​ 验证的目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求(格式),而且不会危害虚拟机自身的安全(安全)。四个阶段的验证:文件格式的验证、元数据的验证、字节码验证和符号引用验证。

  1. 文件格式的验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,该验证的主要目的是保证输入的字节流能正确地解析并存储于方法区之内。经过该阶段的验证后,字节流才会进入内存的方法区中进行存储,后面的三个验证都是基于方法区的存储结构进行的。
  2. 元数据验证:对类的元数据信息进行语义校验(其实就是对类中的各数据类型进行语法校验),保证不存在不符合Java语法规范的元数据信息。
  3. 字节码验证:该阶段验证的主要工作是进行数据流和控制流分析,对类的方法体进行校验分析,以保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为。
  4. 符号引用验证:这是最后一个阶段的验证,它发生在虚拟机将符号引用转化为直接引用的时候(解析阶段中发生该转化,后面会有讲解),主要是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验。
准备

类变量赋0值

​ 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:

  1. 这时候进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。

  2. 这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。

解析

解析阶段是虚拟机将常量池中的符号引用转化为直接引用的过程。 对同一个符号引用进行多次解析请求时很常见的事情,虚拟机实现可能会对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并把常量标示为已解析状态),从而避免解析动作重复进行。

解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行,分别对应于常量池中的四种常量类型。

   1. 类或接口的解析
      判断所要转化成的直接引用是对数组类型,还是普通的对象类型的引用,从而进行不同的解析。
   2. 字段解析
      对字段进行解析时,会先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,如果有,则查找结束;如果没有,则会按照继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口,还没有,则按照继承关系从上往下递归搜索其父类,直至查找结束
初始化

五种必须马上初始化类的情况:(称为主动引用,而不会立即初始化的情况称为被动引用)

**记:**主父反射,new static

  1. new指令 三种static指令(get put invoke + static)

  2. 反射方法调用类

  3. 初始化类时,先初始化其所有父类(递归初始化)
    类在初始化时,要求其父类全部已经初始化过了,而接口不必初始化父接口,只在使用的时候才初始化(如引用接口中定义的常量)

  4. 主类(运行程序时main方法的类)最先初始化

  5. 不常见 见《JVM》p211.

    代码案例等详见《JVM》p211


类加载器


java中类的加载连接和初始化都在程序运行期间进行,用轻微性能代价为Java提供了高灵活性(cpp在编译时进行连接)。java的可动态扩展的语言特性来源于此。

jvm表示同一个类的两个条件
  1. 类名完全一致
  2. 由同一个classloader加载
双亲委派模型

这种层次关系称为类加载器的双亲委派模型。我们把每一层上面的类加载器叫做当前层类加载器的父加载器,当然,它们之间的父子关系并不是通过继承关系来实现的,而是使用组合关系来复用父加载器中的代码。

双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

无论是哪个类加载器要加载此类,最终都会委派给启动类加载器进行加载,保证了Object类在程序中的各种类加载器中都是同一个类。

逻辑结构为多叉树

OSGi的类加载器架构

java世界的模块化标准,广泛应用。

  1. 没有父子关系,所有的bundle(模块)为平级关系;
  2. 根据发布和引用package,来决定引用依赖关系
  3. 其逻辑结构由树(双亲委派)-> 图
  4. 可能死锁:循环引用
    解决:单线程串行加载
  5. 《jvm》p280.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值