• JVM的类加载机制


    1、概述:JVM是Java语言实现跨平台的关键Java语言的运行过程:

            *.java通过编译器编译为*.class,通用字节码文件并不能直接被操作系统所识别,针对不同的操作系统可安装对应的JVM,JVM将字节码解释为当前平台所能识别的机器码实现“跨平台”。

    JVM执行class文件的方式:解释为主,编译为辅

    解释:将字节码解释为操作系统能识别的机器码

    编译:对于出现次数较多的“热点”指令直接编译为机器码存储在缓存中(JIT)

    2、JVM的组成结构

    JVM由类加载器、运行时数据区域、执行引擎、本地方法接口四部分组成

    3、类加载过程

    JVM要将字节码解释为机器码,首当其冲需要将字节码加载到JVM内存中,这个过程叫做类加载。

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

    第一步:加载(三件事)

            一、根据完全限定名读取二进制字节流

            二、将字节流所代表的静态存储结构转换为方法区(元空间)的运行时数据结构

            三、生成类的 Class 对象,作为方法区各种数据的访问入口。

    第二步:验证——验证字节码中字节流信息是否符合当前JVM要求,并不会危害JVM的自身安全

    第三步:准备——为类变量分配内存并设置初始化值

    第四步:解析——将常量池符合引用替换为直接引用

    第五步:初始化——执行(包含静态变量赋值与静态代码块)

            注意:定义在静态代码块之后的类变量,只能赋值,不能访问

    经历上述5个步骤后,类已经被加载至JVM内存中。那么在什么情况下一个类会被加载呢? 

    4、类加载时机

          触发类加载的常见场景有以下5种情况:

    一、new一个对象、访问类变量、为类变量赋值、调用类方法(new、getstatic、putstatic、  invokestatic指令)

    二、对类的反射调用(Class.forName()或newInstance()

    三、预加载类的父类未加载时,先加载父类

    四、程序入口方法所在类会加载

    五、接口中定义了默认方法,在实现类加载前会先加载接口

    注意:接口中虽无法定义静态代码块,但仍有静态变量的存在,与类不同的是,接口的类加载不会触发父接口的类加载,只有在使用到了父接口才会对父接口类加载,同样实现类也一样,未使用父接口中的资源时不加载父接口(定义了默认方法的接口例外)

            同样也有几种场景情况下不会进行类加载需要我们了解,以免混淆

    一、通过子类引用访问父类的类变量,子类不加载

    二、数组定义的引用类,不触发类加载,JVM会将数组类自动生成为Object的子类

    三、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的加载。

    类加载的过程已经何时会进行类加载我们已经了解了,那么谁来执行类加载呢,它需要依靠一个叫类加载器的结构完成这一步骤,类加载器属于前面JVM组成接口的一部分。

    5、类加载器——执行类加载

    类加载器针对加载类不同分为3大类:

            一、启动类加载器(Bootstrap ClassLoader):加载基础、核心类库

            二、扩展类加载器(Extension ClassLoader):加载扩展类库,父类加载器为Bootstrap ClassLoader

            三、应用程序类加载器/系统类(Bootstrap ClassLoader):加载自定义类与第三方jar包类库,父类加载器为Extension ClassLoader

    这三个类加载它们各司其职,但存在层次结构关系,类加载器之间的层次关系被称为双亲委派模型

    双亲委派模型的工作原理类加载器首先会将类加载请求转发至父类加载器,若父类加载器完成不了时,它才会自行加载。

    这样干究竟有什么目的?

    例如:java.util.lang包下有一个Object类(存放在rt.jar【由启动类加载器加载】),我们同样自定义了一个java.util.lang包下的Object类放到 ClassPath 中(由应用程序类加载器加载)。由于rt.jar 中的 Object 优先级更高,那么程序中使用的所有的 Object 都是由启动类加载器所加载的Object。

    作用:使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一,避免冲突

  • 相关阅读:
    SICP:元循环求值器(Python实现)
    Javaweb之Vue生命周期的详细解析
    [ubuntu系统下的文本编辑器nano,vim,gedit,文件使用,以及版本更新问题]
    Java之Spring MVC中表单标签的简介说明
    【vue3】for循环多选框勾选必填校验
    驱动开发:内核测试模式过DSE签名
    脚本性能转换
    前端开发纷繁复杂,是否有更高效的开发方式?
    Scala010--Scala中的常用集合函数及操作Ⅰ
    1、深入了解MySQL中内部组件架构(连接器,查询缓存,分析器,优化器,执行器等)
  • 原文地址:https://blog.csdn.net/weixin_53988377/article/details/132883261