java虚拟机加载类_总结JVM(java虚拟机) 类加载器

类加载器

类加载器是用来完成类的加载的。

7748add48497346287acbb1cec9e8db2.png

一、JVM中类加载器相关的基本概念

(1)类的加载和卸载

JVM将指定的class文件读取到内存里,并运行该class文件里的java程序的过程,就称之为“类的加载”;

反之,将某个class文件的运行时数据从JVM中移除的过程,就称之为“类的卸载”。

(2)类的生命周期

Java类从被虚拟机加载开始,到卸载出内存为止,它的生命周期包括:

加载(Loading)、

验证(Verification)、

准备(Preparation)、

解析(Resolution)、

初始化(Initialization)、

使用(Using)、

卸载(Unloading)

7个阶段。

其中验证、准备、解析又称为连接(Linking)阶段。

ef6a16d2c6ac46c9aef94ac9428da7ac.png

二、类加载过程

类加载过程:Class文件被JVM加载至JVM内存,在内存中验证、准备、解析、初始化之后,形成可以被JVM直接使用的java类型。

类加载过程是在Java程序运行期间完成,虽然会损耗一部分性能,但提高了Java语言的灵活性,体现在动态扩展方面,例如:多态(晚期绑定)。

7b2fe0518c9492b148e45017d7b19a30.png

类加载主要有以下几个步骤:

1、加载:在机载阶段,虚拟机主要完成以下三件事情:

1)通过class文件的路径读取到二进制流。

2)解析二进制流将里面的元数据(类型、常量等)载入到方法区。

3)在java堆中生成对应的java.lang.Class对象。

2、连接

连接过程又分为3步,验证、准备、解析

2.1、验证:判断class文件的合法性

2.2、准备:分配内存,给类的一些字段设置初始值。

比如:

public static int a = 1;在准备阶段a的值会初始化为0,到后面的初始化时才会设置为1.

public final static int b = 1;在准备阶段就会被设置成指定的值,即b在准备阶段设为1。

2.3、解析:将符号引用替换成直接引用。

比如:某个类继承Object,原来的符号引用记录的是“java.lang.object”这个符号,但不能找到该对象在哪。

直接引用就是要找到“java.lang.object”所在的内存地址,建立直接引用关系,这样就方便查询到具体对象。

3、初始化:主要包括执行类构造方法、static变量赋值语句、static{}语句块

需要注意的是:

一个类进行初始化,那么会先初始化其父类,保证父类在子类之前被初始化。

所以在java中初始化一个类,必先初始化java.lang.object,因为所有的java类都继承java.lang.object。

三、类加载器以及双亲委派模式

类加载器有一下几个:

1. 引导类加载器(Bootstrap ClassLoader):在jvm运行时,内嵌在jvm中的一段特殊的用来加载java核心类库的C++代码。

2. 扩展类加载器(Extension ClassLoader):用来加载jvm实现的一个扩展目录,该目录下的所有java类都由此类加载器加载。

3.应用类加载器(Application ClassLoader):又称系统类加载器,主要负责加载程序开发者自己编写的java类。

4. 自定义加载器(Custom ClassLoader):通过java.lang.ClassLoader的子类自定义加载class。

a5f4c8c8168ee80a5b9fd34e5edd2ebe.png

在选用类加载器的时候,先会自下向上检查类是否被加载,

那么从Application ClassLoader 到 Bootstrap ClassLoader 检查是否被加载了(通过findLoaderClass),如果没有加载,则会交给父类,直到没有父类。

如果仍然没有,自顶向下尝试加载类,

那么从Bootstrap ClassLoader 到 App ClassLoader依次尝试加载。

双亲委派模型:

如果一个类加载器收到了某个类的请求,则该类加载器并不会加载该类,而是把这个请求委派给父类加载器,每一个层次类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的启动类加载器;

只有当父类加载器,在其搜索范围内无法找到所需的类,并将该结果反馈给子类加载器,子类加载器会尝试去加载。

这就是双亲委派模型。

备注:

不同的类加载器加载同一类,加载后的对象是完全不一样的。

即使两个类来源于相同的class文件,如果使用不同的类加载器,加载后的对象是完全不同的。

这个不同反应在对象的equals()、isAssignableFrom()、isInstance()等方法的返回结果,包括了使用isntanceof关键字对对象所属关系的判定结果。

为什么使用双亲委派?

一个是安全性,另一个就是性能;(避免重复加载 和 避免核心类被篡改)

破坏双亲委派模式

个人觉得不是重点,但提一下。

例子:Tomcat的WebappClassLoader 就会先加载自己的Class,找不到再委托parent;

双亲模式是默认的模式,但不是必须这么做;

由于用户对程序动态性的追求导致的,这里所说的“动态性”指的是当前一些非常“热门”的名词:代码热替换、模块热部署等,简答的说就是机器不用重启,只要部署上就能用。

举例:

OSGi实现模块化热部署的关键则是它自定义的类加载器机制的实现。每一个程序模块(Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。

本文地址:https://blog.csdn.net/github_37130188/article/details/110262141

希望与广大网友互动??

点此进行留言吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值