Java虚拟机类加载机制

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

 

类加载的时机

类加载的生命周期:加载—>验证-准备-解析—>初始化—>使用—>卸载

————————————

连接中

加载与连接阶段是交叉进行的

什么时候虚拟机必须对类进行初始化

1、遇到new、getStatic、putStatic或者invokeStatic字节码指令时

使用new关键字实例化对象的时候

读取或者设置一个类静态字段

调用一个的静态方法

2、使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化

3、父类还没有初始化的时候,需要先触发其父类的初始化

4、虚拟机启动时,用户需要指定一个执行的主类,虚拟机会先初始化这个子类

5、JDK1.7后,如果MethodHandle实例最后解析结果为REF_getStatic,REF_putStatic、REF_invokeStatic的方法句柄,而这个方法对应的类还没有进行初始化,则先触发其初始化。

 

在invoke指令、反射、执行主类等动作之前,MethodHandle实例解析后,开始对类进行初始化

 

类加载的过程

 

加载

加载阶段:

1、通过一个类的全限定名来获取该类的二进制字节流

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

3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

 

数组类

对于数组类而言,数组类不通过类加载器创建,由jvm直接创建,但数组类的元素类型最终还是要靠类加载器去创建

1、组件类型是引用类,递归采用加载过程去加载这个组件类型,数组将在加载该类型的类加载器的类名称空间上被标记。

2、如果数组组件不是引用类,JVM将会把数组标记为与引导类加载器关联

3、数组类型的可见性与组件类型的可见性一致,如果组类类型不是引用类,那么默认可见行为public

 

验证

文件格式验证

是否符合class文件格式规范

 

元数据验证

对元数据信息进行语义分析,保证不存在不符合Java语言规范的元数据信息

 

字节码验证

通过数据流和控制流分析,验证程序语义是否合理,保证在运行时不会做出危害虚拟机安全的事件

 

符号引用验证

发生在将符号引用转换为直接引用的时候,这个转换动作将在解析时发生,保证解析动作能够正常运行。

 

准备

正式为类变量分配内存并设置类变量初始值的阶段,这些变量将在方法区中被分配。被分配的只包括类变量(被static修饰的变量),不包括实例变量,实例变量会在对象实例化的时候随着对象一起分配在Java堆中。

 

解析

虚拟机将常量池内的符号引用替换为直接引用的过程

符号引用:以一组符号来表示所引用的目标

与内存布局无关

引用的目标并不一定已经加载到内存中

直接引用:是直接指向目标的指针、相对偏移量、间接定位到目标的句柄

与虚拟机实现的内存布局相关

有了直接引用,引用目标必定已经在内存中

 

类或接口解析:

如果需要将一个符号引用N,解析为一个类或者接口C的直接引用,需要一下3个步骤:

1、如果C不是一个数组类型,那虚拟机会把代表N的权限定名传递给D的类加载器去加载这个类C,在加载过程中会触发其他类加载动作,例如加载父类或者是接口实现类,一旦异常,即解析失败。

2、如果C是一个数组类型,并且数组元素是以[Ljava.lang.Integer的形式,那么会按照第一条的规则来加载数组元素类型

3、如果上面的步骤没有出现任何异常,那么C在虚拟机中已经是一个有效的类或接口了,但在解析完成前,还需要进行符号引用验证,判断是否有权限进行访问。IlegalAccessError

字段解析:

类方法解析:

类方法解析的第一步,也是需要解析出类方法表的class_index项中索引的方法所属的类或者接口的符号引用,如果解析成功

1、类方法和接口方法的符号引用是分开的,如果发现类方法表中class_index索引是个接口,那么直接异常

2、在C中类查找是否有简单名称和描述相匹配的方法,如果有,则返回这个方法的直接引用,查找结束

3、在父类中查找是否有简单名称和描述相匹配的方法

4、在类C实现的接口列表及他们的父接口之中递归查找

5、否则宣告方法查找失败

接口方法解析:

1、与类方法相似,如果方法接口方法中class_index索引是个类,那么直接异常

2、在接口C中查找是否有简单名称和描述相匹配的方法

3、在接口C的父接口中递归查找,直到找到为止

4、接口中的所有方法都是默认public的,所以不存在访问权限的问题

初始化:

初始化阶段是执行<client>()方法的过程

 

类加载器

将“通过一个类的全限定名来获取类的二进制字节流“这个动作放到Java虚拟机外部实现,让程序自己去获取需要的类

 

双亲委派模型

 

启动类加载器:

1、这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或者说是-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库加载到虚拟机内存中

2、启动类加载器无法被Java程序调用

 

扩展类加载器:

1、负责加载<JAVA_HOME>\lib\ext的扩展类库

2、开发者可以直接使用

 

应用程序加载器:

1、负责加载用户路径(ClassPath)上指定的类库

2、开发者可以直接使用

3、应用程序中没有自定义过自己的类加载器,一般情况下,这个就是默认加载器

 

 

双亲委派模型的工作过程:

如果一个类加载器收到了类加载请求,它不会自己尝试加载这个类,而是把请求委派给父类加载器去完成,每层如此,只有当父类加载器反馈说无法查找到此类,才会尝试自己去加载

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值