JVM之类加载机制

虚拟机类加载机制

类加载的概念

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

类加载的时机

Java语言里面,类型的加载,连接,初始化过程都是在程序运行期间完成的,这种策略让java语言进行提前编译会面临额外的困难,也会让类加载时稍微增加一些性能开销,但是却为java应用提供了极高的扩展性和灵活性,Java天生可以动态扩展的语言特性就是依赖运行期间动态加载和动态连接的这个特点实现的。

类加载的过程

一个类从被加载到内存虚拟机内存中,到卸载出内存为止,整个生命周期为:加载、验证、准备、解析、初始化、使用、卸载,七个阶段,其中验证,准备,解析阶段统称为连接。

在这里插入图片描述

加载

加载阶段是类加载过程的第一个阶段,此阶段虚拟机需要完成三件事:

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

验证

验证是连接阶段的第一步,这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

验证分为四个阶段:文件格式验证、元数据验证、字节码验证、符号引用验证。

准备

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始化值的阶段,从概念上讲,这些变量所使用的内存都应当在方法区进行分配,但必须注意到方法区本身是一个逻辑上的区域,在JDK7之前,HotSpot使用永久代来实现方法区时,实现是完全符合这种逻辑概念的;而JDK8及以后,类变量则会随着Class对象一起存放在Java堆中,这时候“类变量在方法区”就完全是一种对逻辑概念的表述。

比如:int i= 100;在准备阶段给它赋予初始值为0,直到初始化阶段i才被赋值为100。

解析

解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用:符号引用一组符号来描述引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位目标即可。符号引用于虚拟机时间的内存布局无关,引用的目标并不一定是已经加载到虚拟机内存当中的内容。各种虚拟机实现的内存布局可以各不相同,但是它能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在《Java虚拟机规范》的Class文件格式中。

直接引用:直接引用是可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局直接相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在虚拟机的内存中存在。

解析又分为:类或接口解析、字段解析、方法解析、接口方法解析

初始化

类的初始化阶段是类加载过程的最后一步,java虚拟机开始执行类中编写的java程序代码,将主导权移交给应用程序。

初始化过程中代码块加载顺序

  • 同一个类的执行顺序

静态代码块—>构造代码块—>构造函数

  • 继承中的执行顺序

父类的静态代码块—>子类的静态代码块—>父类的构造代码块—>父类的无参构造函数—>子类的构造代码块—>子类的构造函数

普通代码块和同步代码块的顺序取决于代码块的位置。

类加载器

概念

通过一个类的全限定名来描述该类的二进制字节流。

如何判断两个类是否“相等”?

比较两个类是否“相等”,只有这两个类是有同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个Java虚拟机加载,只要加载他们的类加载器不同,那么这两个类就必定不相等。

双亲委派模型

首先了解一下三层加载器:启动类加载器、扩展类加载器、应用程序加载器

启动类加载器:负责加载存放在<JAVA_HOME>\lib目录,或者被-Xbootclasspath参数所指定的路径中存放的,而且是java虚拟机能识别的类库加载到虚拟机内存中。

扩展类加载器:负责加载存放在<JAVA_HOME>\lib\ext目录中,或者被java.ext.dirs系统变量指定的路径中的所有类库。

应用程序类加载器:负责加载用户类路径(ClassPath)上所有的类库。

什么是双亲委派模型?

各种类加载器之间的层级关系被称为类加载器的双亲委派模型。

双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。不过这里类加载器之间的父子关系一般不是继承的关系来实现的,而是通常使用组合关系来复用父类加载器的代码。

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

如果一个类加载器收到了类加载请求,它首先不会自己尝试加载这个类,而是把这个请求为派给父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去完成加载。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值