JVM 学习—— 类加载机制

前言

        在上一篇文章中,荔枝梳理了有关Java中JVM体系架构的相关知识,其中涉及到的有关Java类加载机制的相关知识并没有过多描述。那么在这篇文章中,荔枝会详细梳理一下有关JVM的类加载机制和双亲委派模型的知识,希望能够帮助到有需要的小伙伴~~~


文章目录

前言

一、JVM中类加载过程

加载

连接

初始化

二、类加载器

类加载器的分类 

类加载器的特点

三、双亲委派机制

双亲委派机制流程

双亲委派机制的优点

如何打破双亲委派机制 

总结


一、JVM中类加载过程

        在前面JVM体系结构一文中我们知道运行Java程序的过程首先编译器会将.Java文件编译成字节码文件并由JVM中的类加载机制进行加载和并发送指令给执行引擎执行。而对于类来说,它的生命周期主要经历7个阶段:加载、验证、准备、解析、初始化、使用、卸载,其中前五个阶段就是类加载的过程。需要注意的是,类加载过程并不是严格意义上的按顺序经历上面的五个阶段,这些阶段可能会互相混合、交叉运行。接下来看看五个阶段的类加载的内容:

加载

        加载阶段是将类的字节码文件加载到JVM中的内存中,并在内存中生成对应的Class对象。类加载器根据类的全限定名(类的包名+类名)来查找字节码文件,找到后读取字节码数据,转化成方法区的运行时数据结构并在Java堆中生成对应的Java.lang.Class对象,作为对方法区中这些数据的访问入口。

类加载器可以是Java虚拟机自带的类加载器,也可以是自定义的类加载器。

连接

我们一般把验证、准备和解析这三个状态归到一块作为连接的阶段, 连接阶段将类的字节码文件中的符号引用转换为直接引用,生成可执行的代码。

验证

验证阶段的目的是保证字节码文件中的字节流内容符合Java虚拟机的规范。一般来说验证阶段会进行文件格式验证、元数据验证、字节码验证和符号引用验证。

  • 文件格式验证:验证字节流是否符合Class文件格式的规范。例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型;
  • 元数据验证:对字节码描述的元数据信息进行语义分析,要符合Java语言规范。例如:是否继承了不允许被继承的类(例如final修饰过的)、类中的字段、方法是否和父类产生矛盾等;
  • 字节码验证:对类的方法体进行校验分析,确保这些方法在运行时是合法的、符合逻辑的。
  • 符号引用验证发生在解析阶段,符号引用转为直接引用的时候,例如:确保符号引用的全限定名能找到对应的类、符号引用中的类、字段、方法允许被当前类所访问等等

准备

在准备阶段类的静态字段信息会得到内存分配,并设置为初始值,其中静态字段信息指的是被static关键字修饰的变量。

解析

这个阶段,虚拟机会把这个Class文件中,常量池内的符号引用转换为直接引用。主要解析的是类或接口、字段、类方法、接口方法、方法类型、方法句柄等符号引用。

初始化

        初始化阶段是类加载的最后一个阶段,也是真正执行类的初始化代码块和静态变量初始化的阶段。在这个阶段,JVM会按照程序员指定的顺序执行类的静态初始化代码块和静态变量的初始化,这些初始化代码会在类第一次使用时被调用。初始化是类加载过程中的最后一个步骤,直到此阶段完成,类才算完全加载并可以使用。 

需要注意的是:在整个类加载过程中,类加载器负责加载和连接阶段,而初始化阶段由JVM负责。 


二、类加载器

类加载器,其实就是一个可以将Java编译后的字节码文件加载为可以被java.lang.class实例化的工具,负责将字节码文件转化成为JVM内部的Class对象。

类加载器的分类 

启动类加载器(Bootstrap ClassLoader):负责加载%JAVA_HOME%/lib 目录,或者被 -Xbootclasspath 参数制定的路径,例如 jre/lib/rt.jar 里所有的class文件。由C++实现,不是ClassLoader子类。

拓展类加载器(Extension ClassLoader):负责加载Java平台中扩展功能的一些jar包,包括<JAVA_HOME>\lib\ext 目录中 或 java.ext.dirs 指定目录下的jar包。由Java代码实现。

应用程序类加载器(Application ClassLoader):我们自己开发的应用程序,就是由它进行加载的,负责加载ClassPath路径下所有jar包。

自定义类加载器(User ClassLoader):通过继承java.lang.ClassLoader实现自定义的类加载 

类加载器的特点

  • 按需加载:无需在程序一开始运行的时候加载所有的字节码文件,而是在程序运行的过程中,动态按需加载,字节码的来源也很多,压缩包jar、war中,网络中,本地文件等。类加载器按需加载的特点为热部署,热加载做了有力支持。
  • 全盘负责:当一个类加载器加载一个类时,这个类所依赖的、引用的其他所有类都由这个类加载器加载,除非在程序中显式地指定另外一个类加载器加载。所以破坏双亲委派不能破坏扩展类加载器以上的顺序。
  • 双亲委派:类加载器遵循双亲委派模型,即加载类时,首先委派给父类加载器处理。只有父类加载器无法加载时,才由子类加载器尝试加载。双亲委派模型保证了类的加载在整个类加载器层次中的一致性,避免类的重复加载和冲突。
  • 自定义扩展:开发者可以继承java.lang.ClassLoader类,实现自定义的类加载器。通过自定义类加载器,可以实现特定的类加载行为,打破双亲委派模型,加载特定位置的类文件,满足特定需求。

三、双亲委派机制

        JVM 并不是在启动时就把所有的Class文件都加载一遍,而是程序在运行过程中用到了这个类才去加载,而通常这个类加载过程就会基于双亲委派机制来实现。双亲委派是JVM中对类加载的一种模式机制,即任意一个类在接到一个类的加载请求时,都会先加载其父类,若父类无法加载(或无父类)的情况下,再尝试自己加载或者给子类加载,总的来说就是向上委派、向下加载的过程。

双亲委派机制流程

用直白的语言来描述一下双亲委派的流程:

  • 在当前的类加载器收到类加载请求时,会首先检查是否之前加载过该类,如果加载过就将该类所对应的Class对象返回出去并完成类加载请求响应。
  • 如果该类没有被加载过,当前的类加载器则会将该加载请求委派给父类加载器处理。父类加载器按照同样的递归方式向上委派该类加载请求,即首先检查该类是否已经被加载过,如果已经被加载过,则返回对应的Class对象。如果父类加载器也没有加载过这个类,则将加载请求再委派给父类的父类的加载器,直到达到顶层的启动类加载器。
  • 如果顶层的启动类加载器也没有加载过这个类,则当前类加载器尝试自己加载这个类。如果启动类加载器加载该类失败(加载路径下找不到该class文件),就会将加载向下委派给其子类的类加载器直至自定义类加载器;
  • 如果自定义类加载器也无法加载该类,就会排除ClassNotFound异常。

双亲委派机制的优点

前面我们已经知晓双亲委派机制是向上委派、向下加载的。这种执行方式就能够有效保证了类都是在同一个类加载器中加载并构造对象的。同时由于类总是从父类中开始加载的,也保证了官方JDK代码包的安全性,具体的优点如下:

  1. 避免类的重复加载:通过双亲委派机制,当一个类加载器加载一个类时,它会首先委派给父类加载器处理。如果父类加载器已经加载了这个类,就不需要再次加载,直接返回已加载的Class对象。这样可以避免同一个类被不同的类加载器加载,保证类的唯一性,避免类的重复加载,节省了内存空间。

  2. 保证代码安全性:通过双亲委派机制,JVM的核心类库(如java.lang、java.util等)由启动类加载器加载,这些类库被放置在JVM的核心路径下,由Java官方提供,保证了这些类的安全性和稳定性。用户自定义的类则由应用类加载器加载,用户可以控制这些类的访问权限,从而提高了应用程序的安全性。

  3. 确保类的一致性:通过双亲委派机制,JVM保证了类加载的一致性。无论是系统核心类库还是用户自定义的类,它们都是由类加载器层次结构中的某个类加载器加载的,这样可以保证类在整个JVM中的唯一性和一致性,避免类的冲突和不一致性。

  4. 代码隔离:双亲委派机制将类的加载委派给父类加载器处理,子类加载器无法直接访问父类加载器加载的类,这样实现了类加载器之间的代码隔离。不同的类加载器可以加载相同名称的类,但它们加载的类是不同的,从而实现了类的隔离,不同的类加载器可以加载自己的版本,相互之间不会相互干扰。

如何打破双亲委派机制 

        在某些特定的场景下,我们需要打破JVM类加载中的双亲委派机制,比如我们想要加载一些于JVM核心类库同名的类并且希望这些类由用户自定义的类加载器加载,而不是受到父类加载器的影响。打破双亲委派机制的两种方式:

  • 自定义类加载器并继承ClassLoader类,重写该类的方法如findClass和loadClass;
  • 通过线程上下文类加载器的传递性并让父类加载器调用子类加载器的加载动作。

总结

        以上就是JVM中有关类加载机制的相关知识点了,其中最重要的就是双亲委派机制的理解和两种打破方式的了解,这里其实荔枝写的不是特别详细,可能需要在阅读完源码之后才能输出更有质量的自我理解吧。大致了解了JVM的类加载机制,接下来的文章中荔枝可能会输出有关JVM另一个核心知识点:GC垃圾回收机制的相关知识的梳理,希望能够帮助到大家哈哈哈~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/22100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时间复杂度接近O(n)的三种排序算法

1.桶排序 桶排序&#xff0c;顾名思义&#xff0c;会用到“桶”&#xff0c;核心思想是将要排序的数据分到几个有 序的桶里&#xff0c;每个桶内的数据再单独进行排序。桶内排完序之后&#xff0c;再把每个桶内的数据按照顺序依次 取出&#xff0c;组成的序列就是有序的了。 …

使用vue creat搭建项目

一、查看是否安装node和npm&#xff08;显示版本号说明安装成功&#xff09; node -v npm -v 显示版本号说明安装成功&#xff0c;如果没有安装&#xff0c;则需要先安装。 二、安装vue-cli脚手架 查看安装的版本&#xff08;显示版本号说明安装成功&#xff09; vue -V 三…

【雕爷学编程】 MicroPython动手做(35)——体验小游戏3

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

30. 利用linprog 解决 生产决策问题(matlab程序)

1.简述 线线规划的几个基本性质&#xff1a;【文献[1]第46页】 (1)线性规划问题的可行域如果非空&#xff0c;则是一个凸集-凸多面体&#xff1b; (2)如果线性规划问题有最优解&#xff0c;那么最优解可在可行域的顶点中确定&#xff1b; (3)如果可行域有界&#xff0c;且可行域…

企业电子招投标系统源码之电子招投标系统建设的重点和未来趋势 tbms

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为…

tfserving

文章目录 部署测试模型传参优化 部署 docker run -dit -p 8501:8501 -p 8500:8500 -v /data1/minisearch/modelzoo/deepfm/models:/models/deepfm -e MODEL_NAMEdeepfm -e TF_CPP_MIN_VLOG_LEVEL1 $image_nameTF_CPP_MIN_VLOG_LEVEL1设置打印日志类型&#xff0c;如下 2023-0…

SpringBoot + ajax 实现分页和增删查改

0目录 1.SpringBoot 2.SpringBoot分页&#xff1b;增删改查 1.SpringBoot分页 创建数据库和表 创建SpringBoot工程&#xff0c;引入springboot下的分页依赖 配置application.yml 实体类 Mapper接口 Mapper.xml Service接口 Service实现类 控制层 测试 加…

Kotlin单例代码实例

目录 一、饿汉式的实现二、懒汉式的实现三、安全 懒汉式的实现四、双重校验DCL 的实现 一、饿汉式的实现 Kotlin版本 object SingletonDemoKt/*** 背后的逻辑代码&#xff1a;public final class SingletonDemoKt {public static final SingletonDemoKt INSTANCE;private Si…

新手Vite打包工具的使用并解决yarn create vite报错

一、手动创建 1.创建vite-Demo文件夹 2.初始化 yarn init -y 3.安装vite yarn add -D vite 4.打包准备 说明&#xff1a;不需要在src下面创建&#xff0c;在vite-Demo文件夹创建 4.1index.js文件 document.body.insertAdjacentHTML("beforeend","<h1>…

Linux6.30 Kubernetes 基础

文章目录 计算机系统5G云计算第一章 LINUX Kubernetes 基础一、Kubernetes 概述1.K8S 是什么2.为什么要用 K8S3.Kubernetes 集群架构与组件4.核心组件——Master 组件1&#xff09;Kube-apiserver2&#xff09;Kube-controller-manager3&#xff09;Kube-scheduler 5.核心组件—…

kafka生产者指定ip

kafka生产者指定ip 最近工作中遇到一个问题&#xff0c;记录一下&#xff0c;需求中要求往kafka上推送信息。本来是个很简单的需求&#xff0c;但是踩了一个坑。 ​ 我通过spring boot集成了kafka写了一个生产者&#xff0c;客户那边给我三个节点的ip&#xff0c;然后我也没多想…

【uniapp APP隐藏顶部的电量,无线,时间状态栏与导航栏】

uniapp APP隐藏顶部的电量&#xff0c;无线&#xff0c;时间状态栏 如下代码配置&#xff08;在一个页面设置这个段代码&#xff0c;所有页面都会消失&#xff09; onShow() {// #ifdef APP-PLUS// 隐藏顶部电池,时间等信息 plus.navigator.setFullscreen(true);//隐藏虚拟按…

排序八卦炉之冒泡、快排【完整版】

文章目录 1.冒泡排序1.1代码实现1.2复杂度 2.快速排序2.1人物及思想介绍【源于百度】2.2hoare【霍尔】版本1.初识代码2.代码分析3.思其因果 2.3挖坑版本1.初始代码2.代码分析3.思想比较 2.4指针版本1.初识代码2.代码分析3.问题探讨 2.5集体优化2.6极致优化2.7非递归版本1.初识代…

sql语句字符函数,数学函数

一、trim&#xff08;&#xff09;去掉前后单元格 SELECT LENGTH(TRIM( 张三 )) AS 姓名 trim&#xff08;aa from bb) 除掉bb中前后包含的aa&#xff0c;中间的保留 SELECT TRIM(班 FROM class) AS 姓名 FROM user_test 二、lpad&#xff08;&#xff09;用指定字符做左…

用Rust实现23种设计模式之桥接模式

桥接模式的优点&#xff1a; 桥接模式的设计目标是将抽象部分和实现部分分离&#xff0c;使它们可以独立变化。这种分离有以下几个优点&#xff1a; 解耦和灵活性&#xff1a;桥接模式可以将抽象部分和实现部分解耦&#xff0c;使它们可以独立地变化。这样&#xff0c;对于抽象…

【css】css实现一个简单的按钮

四种链接状态分别是&#xff1a; a:link - 正常的&#xff0c;未访问的链接a:visited - 用户访问过的链接a:hover - 用户将鼠标悬停在链接上时a:active - 链接被点击时 <style> a:link, a:visited {//未访问、访问过background-color: #07c160;//设置背景颜色color: wh…

Day10-NodeJS和NPM配置

Day10-NodeJS和NPM 一 Nodejs 1 简介 Nodejs学习中文网:https://www.nodeapp.cn/synopsis.html Nodejs的官网:https://nodejs.org/ 概念:Nodejs是JavaScript的服务端运行环境.Nodejs不是框架,也不是编程语言,就是一个运行环境. Nodejs是基于chrome V8引擎开发的一套js代码…

Java设计模式——类之间的关系

1.继承关系(泛化) 类与子类的关系&#xff0c;指一个类继承另外的一个类。 2.实现关系 一个类可以实现多个接口&#xff0c;实现所有接口的功能。 3.依赖关系 类B作为类A方法中的局部变量或者参数出现&#xff0c;表示A依赖B。 4.关联关系 类B作为类A中的成员变量出现&#…

Toyota Programming Contest 2023#4(AtCoder Beginner Contest 311)D题题解

文章目录 [Grid Ice Floor](https://atcoder.jp/contests/abc311/tasks/abc311_d)问题建模问题分析1.分析移动时前后两个点之间的联系2.方法1通过BFS将所有按照给定运动方式可以到达的点都标记代码 3.方法2采用DFS来标记路径上的点的运动状态代码 Grid Ice Floor 问题建模 给定…

linux快速安装Rabbitmq

linux快速安装Rabbitmq 准备yum仓库 # root执行rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.ascrpm --import https://packagecloud.io/rabbitmq/erlang/gpgkeyrpm --import https://packagecloud.io/ra…