欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-10 17:33:48
类加载器类加载器是用来完成类的加载的。一、JVM中类加载器相关的基本概念(1)类的加载和卸载 JVM将指定的class文件读取到内存里,并运行该class文件里的java程序的过程,就称之为“类的加载”; 反之,将某个class文件的运行时数据从JVM中移除的过程,就称之为“类的卸载”。 (2)类的生命周期 Java类从被虚拟机加载开始,到卸载出内存为止,它的生命周期包括: 加载(Loading)、......

类加载器

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

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

 

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


  • (1)类的加载和卸载

        JVM将指定的class文件读取到内存里,并运行该class文件里的java程序的过程,就称之为“类的加载”;
        反之,将某个class文件的运行时数据从JVM中移除的过程,就称之为“类的卸载”。
    

  • (2)类的生命周期

        Java类从被虚拟机加载开始,到卸载出内存为止,它的生命周期包括:
            加载(Loading)、
            验证(Verification)、
            准备(Preparation)、
            解析(Resolution)、
            初始化(Initialization)、
            使用(Using)、
            卸载(Unloading)
        7个阶段。
        其中验证、准备、解析又称为连接(Linking)阶段。

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

 

二、类加载过程


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

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

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

类加载主要有以下几个步骤:
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。

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

在选用类加载器的时候,先会自下向上检查类是否被加载,
那么从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