JVM类的加载相关的问题

JVM类的加载相关的介绍

学习类的加载的加载过程对深入理解JVM有十分重要的作用,下面就跟我一起学习JVM类的加载过程吧!


文章目录

  • JVM类的加载相关的介绍
  • 一、类的加载过程
  • 二、双亲委派机制
    • 1、类加载器的种类
    • 2、为什么JVM要分成不同的类的加载器
    • 3、类的加载过程
    • 4、为什么要通过双亲委派机制
    • 5、从代码层次分析双亲委派机制
  • 三、自定义类加载器
  • 四、打破双亲委派机制
    • 1.tomcat打破双亲委派机制
    • 2.SPI 打破双气双亲委派机制


一、类的加载过程

JVM的类的加载过程分为五个阶段:加载、验证、准备、解析、初始化
加载
  加载阶段就是将编译好的的class文件通过字节流的方式从硬盘或者通过网络加载到JVM虚拟机当中来。(我们平时在Idea中书写的代码就是放在磁盘中的,也可以通过网络加载到虚拟机)

验证
  验证阶段主要是验证class文件的格式或者内容是否符合java规范和虚拟机规范,比如最常见的字节码文件中的cafe baby,以及通过class文件是u2或者u4的的方式解析字节码中各部分的内容是否符合规范。

准备
  准备阶段就是给静态变量(static修饰的变量)赋默认值的过程,int类型的赋值为0,对象类型赋值为null,这都是默认值,需要注意的是常量,也就是被final修饰的static,在类编译的时候就已经赋值完成了。

解析
 解释阶段做的事情用一句话来说就是将符号引用转变为直接引用(句柄)
 句柄:如下如所示虚拟机有两种引种对象数据的方式,一种是通过句柄池的方式,一种是通过直接指针的方式,句柄池的方式就是在引用和真实地址之间多了一层句柄,这样的好处就是当引用的真实对象发生改变时,栈中存放的值不需要改动,但是多了一层就会增加系统的复杂性,所以hotsport虚拟机用的是直接地址指针的方式(如下图)。
直接引用:数据在内存中的真实地址
符号引用: 包括一些方法名和字面量等,这些符号引用在加载过程中有的可以确定下来的,比如static修饰的main方法,这些可以确定下来的引用在解析过程中就会转变为指向真实地址的指针,还有一些是只有在实际运行期间才可以确定下来的,比如多态,接口等,这些就需要到真正调用的时候才转为直接地址引用。(这也就是静态连接和动态连接的区别)

在这里插入图片描述

初始化
类的初始化是将给静态变量赋值(这时候的赋值才是赋代码中书写的值)静态代码块收集在一起进行执行的过程(其实就是执行字节码中的clinit方法,注意这个方法不是类的构造方法)执行顺序根据静态变量和静态代码块在类中的顺序决定。代码如下

public class Hello {//准备阶段给a赋值为0.初始化的时候给a赋值为3public static int a=3;//根据顺序先执行a=3,在实行静态方法static {String b="b";}public static void main(String[] args) {}}

注意:类的初始化,实例化对象


二、双亲委派机制

双亲委派机制是我们学习类的加载和面试过程中逃不掉的问题,接下来我会通过介绍类加载器的种类,jvm虚拟机使通过什么方式调用这些类加载器完成类的加载的,双亲委派机制是什么,打破双亲委派机制的例子有哪些。

1、类加载器的种类

类的加载过程,同通过类加载器实现的。类的加载器主要有如下几种:
引导类加载器:c++代码实现,负责接在java的核心类库,比如rt.jar等
扩展类加载器:加载java的一些扩展类,负责加载jre下ext扩展目录下的jar报
应用类加载器:负责加载classpath下的类,也就是我们自己写的类
自定义类加载器:我们自己写的写的类加载器,负责加载自定义路径下的类

2、为什么JVM要分成不同的类的加载器

介绍为什么要搞这么多类加载器之前,就需要先说明JVM是如何使用这些类加载器的(也就是双亲委派机制)。双亲委派机制就是(引导类加载器->扩展器类加载器->应用类加载器->自定义类加载器 逐层上层是下层类加载器的父亲,注意这里不同于extends的继承关系,是类加载器中有一个parent属性,指向它的父亲是谁)

在这里插入图片描述

在这里插入图片描述

3、类的加载过程

抛开自定义加载器先不谈,当我们自己编的类加载的时候,会先去应用类加载器中查找该类是否已经加载了(如果加载了直接返回),如果没有则向上委托扩展类加载器看它是否已经加载(加载了直接返回),如果没有则继续向上委托(加载了直接返回),若没有加载并且是需要加载核心JAVA的核心类库,则加载如果不是核心类库,则通知下层去加载,如果是JAVA的扩展包的类就通知扩展类加载器加载,如果是用户自定义的类就再由扩展类加载器继续向下通知应用程序加载器加载。这就是JVM的双亲委派机制。

4、为什么要通过双亲委派机制

JVM为什么要通过这种麻烦的方式,来实现类的加载的,原因如下:

  • 沙箱机制:JAVA不希望用户或者黑客随便更改核心类库,所以再加载核心类库和扩展包的时候,JAVA要保证加载的是自己核心类库的东西,而不是别人更改过的类。,就是为了安全
  • 避免了类的重复加载

5、从代码层次分析双亲委派机制

JAVA的双亲委派的机制的主要概念:

  • 引导类加载器由JAVA虚拟机启动以后,调用底层C++代码加载
  • 扩展类加载器和应用类加载器由一个被称为启动器的加载,该类就是Launcher, 扩展类加载器和应用类加载器的上下层父子关系由parent属性确立
  • Launcher类是由引导类加载器加载的

类的关系图

AppClassLoader和ExtClassLoader都是Launcher(启动器)的内部类,由Launcher调用构造方法的时候,创建AppClassLodader和ExtClassLoder
在这里插入图片描述
                      图一

图一
                     图二

AppClassLoader和ExtClassLoder都是继承自URLClassLoader

在这里插入图片描述在这里插入图片描述

URLClassLoader最终继承自ClassLoader

在这里插入图片描述
                     图三
                     
类的父子关系整理清楚了,下面看Launcher是怎么创建AppcClassLloader和ExtClassLoader的?
可以看到,在创建AppClassLoader时,将创建好的ExtClassLoader传给了AppClassLoader的get**方法。这个方法最终直接会调用到它的构造方法,我们直接看它的构造放的代码。
在这里插入图片描述
                     图四

我们看下图AppClassLoader的构造方法,会调用super,也就是父类的构造方法,根据图三的类的关系图,会最终调用到ClassLoader类的构造方法,我们继续进入到它的构造方法中看它干了什么。
在这里插入图片描述
                     图五

好的我们看到了parent属性,也就是将最初传入的ExtClassLoader的实例设置为APPClassLoader的父亲。
tuliu在这里插入图片描述
                    图六

总结:引导类加载器加载了启动器Launcher,Launcher创建了AppClassLoader和ExtClasslLoader,并好父子关系(通过parent)


你以为这就完了吗?,不可能,绝对不可能!双亲委派的代码还没说呢,加载类之前向上委托那一系列的操作,在哪能还没说呢,怎么可能就这么结束了呢!!!


我们来看类是怎么加载的,我们都知道,加载一个类的时候我们会调用ClassLoader的loaderClass方法,那我们就看看父子关系建立好以后,是怎么实现向上委托的?
在这里插入图片描述
                     图七

 public Class<?> loadClass(String name) throws ClassNotFoundException {//调用了重载的loadClass方法,多传入一个flasereturn loadClass(name, false);}
 protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{//加锁是为了保证加载类class文件时,必须是安全的,不会因为并发加载多个类进来synchronized (getClassLoadingLock(name)) {// 先根据类的全限定名查找类是否已经加载过了,加载过了c!=null直接返回。不走下面的代码Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {/*** 注意:这里就是双亲委派的关键代码*代码走到这里会让他的parent去递归调用本方法,直到parent==null时(ExtClassload),这里就符合双亲委派机制,向上委托*///AppClassLoader执行这行代码if (parent != null) {c = parent.loadClass(name, false);//扩展类加载器执行这行代码} else {//因为ExtClassLoader的partent==null执行这行代码,调用引导类加载器,加载java核心类库的代码返回c==null 代码继续向下执行c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();//因为之前是递归调用的,第一次是ExtClassLoader调用这个方法,去加载java扩展包的类//第二次是AppClassLoader调用这个方法,AppCLassLoader是加载classpath路径下我们自己自己写的类,具体实现的方法在URLClassLoader,我们去看URLClassLoader是怎么实现的,如图八c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

在这里插入图片描述
                     图八

加载class流文件
在这里插入图片描述
                       图九

总结

  • 引导类加载器由底层C++代码创建
  • 引导类加载器加载启动器Launcher
  • Launcher的构造方法创建ExtClassLoade和AppClassLoader,并通过parent属性确认父子父子关系
  • ClassLoader的loadClass方式实现了双亲委派机制
  • findClass方法调用defindClass实现classpath下的class文件的加载

在这里插入图片描述
                       图十


三、自定义类加载器

public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}protected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}}public static void main(String args[]) throws Exception {//初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoaderMyClassLoader classLoader = new MyClassLoader("D:/test");//D盘创建 test/com/test/jvm 几级目录,将User类的复制类User1.class丢入该目录Class clazz = classLoader.loadClass("com.test.jvm.User1");Object obj = clazz.newInstance();Method method = clazz.getDeclaredMethod("sout", null);method.invoke(obj, null);System.out.println(clazz.getClassLoader().getClass().getName());}
}

四、打破双亲委派机制

1.tomcat打破双亲委派机制

2.SPI 打破双气双亲委派机制

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

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

相关文章

目标检测框架MMDetection训练自定义数据集实验记录

在上一篇博文中&#xff0c;博主完成了MMDetection框架的环境部署与推理过程&#xff0c;下面进行该框架的训练过程&#xff0c;训练的入口文件为tools/train.py&#xff0c;我们需要配置的内容如下&#xff1a; parser.add_argument(--config,default"/home/ubuntu/prog…

朴素,word,任何参考文献导入endnote

朴素&#xff0c;word&#xff0c;任何参考文献导入endnote 注意&#xff1a;对于以下这几种不做阐述&#xff0c;看其他帖子都有讲述&#xff1a; 这里的参考文献指的是类似于&#xff1a; [1]. Li Y, Lu Y, Huo X, et al. Bandgap tuning strategy by cations and halide io…

github无法访问

1.查看ip ipaddress.com 2.地址如下&#xff1a; 3.修改本地host文件 &#xff08;1&#xff09;打开访达后&#xff0c;在键盘上按ShiftCommandG组合键&#xff0c;进入&#xff0c;在etc找到host文件&#xff0c;修改 &#xff08;2&#xff09;如果修改不成功&#xff0…

【深度学习实验】数据可视化

目录 一、实验介绍 二、实验环境 三、实验内容 0. 导入库 1. 归一化处理 归一化 实验内容 2. 绘制归一化数据折线图 报错 解决 3. 计算移动平均值SMA 移动平均值 实验内容 4. 绘制移动平均值折线图 5 .同时绘制两图 6. array转换为tensor张量 7. 打印张量 一、…

如何移除 ONLYOFFICE 中的插件

如果您需要移除 ONLYOFFICE 编辑器中的某个甚至所有的插件&#xff0c;本文会向您介绍如何操作。如要详细了解&#xff0c;请阅读本文。 为什么会想移除插件 ONLYOFFICE 用户想知道如何删除插件&#xff0c;隐私问题是主要原因之一。有些插件&#xff08;如照片编辑器&#xf…

thinkphp6 入门(5)-- 模型是什么 怎么用

一、模型 MVC架构 之前开发一个功能&#xff0c;后端为在控制器&#xff08;C&#xff09;中写 php SQL&#xff0c;前端为在页面&#xff08;V&#xff09;中写html css js&#xff0c;这就形成了 VC 架构。 但是发现&#xff0c;相同的数据逻辑&#xff08;SQL&#xf…

建筑安全运行监测,预防建筑潜在风险

建筑物是人们生活和工作的场所&#xff0c;其安全性直接关系到人们的生命财产安全。建筑安全运行监测旨在及时发现和识别潜在的安全隐患&#xff0c;以确保建筑物的稳定运行&#xff0c;其重要性不可低估。 建筑安全运行监测可以帮助及早发现结构问题。随着时间的推移&#xff…

优化Docker权限管理:配置Docker用户组

Docker 利用 Linux 的用户和组权限来管理对 Docker 守护进程的访问权限。一般情况下&#xff0c;只有 root 用户和属于 docker 用户组的用户才被允许访问 Docker 守护进程。在 Linux 系统上使用 Docker 时&#xff0c;如果您尚未配置 docker 用户组&#xff0c;那么作为非 root…

企业级智能PDF及文档处理SDK GdPicture.NET 14.2 Crack

企业级智能PDF及文档处理SDK GdPicture.NET 提供了一组非常先进的 API&#xff0c;这些 API 利用了人工智能、机器学习和模糊逻辑算法等尖端技术。经过超过 15 年的持续研究和对创新的专注&#xff0c;我们的 SDK 已成为市场上针对PDF、OCR、条形码、文档成像和各种格式最全面的…

大数据成为市场营销利器 ,促进金融贷款企业获客精准化

随着大数据技术的不断普及&#xff0c;中国对尖端技术和云计算技术的投资大幅增加。大数据、云计算技术、物联网等一系列新一代信息技术也加速完善。 目前&#xff0c;大数据技术也非常成熟&#xff0c;大数据的应用领域也多种多样。大数据的重要方面“运营商大数据”已经被政…

R语言应用interactionR包进行亚组相加交互作用分析

在统计分析中交互作用是指某因素的作用随其他因素水平变化而变化&#xff0c;两因素共同作用不等于两因素单独作用之和(相加交互作用)或之积(相乘交互作用)。相互作用的评估是尺度相关的&#xff1a;乘法或加法。乘法尺度上的相互作用意味着两次暴露的综合效应大于&#xff08;…

java八股文面试[JVM]——JVM性能优化

JVM性能优化指南 JVM常用命令 jps 查看java进程 The jps command lists the instrumented Java HotSpot VMs on the target system. The command is limited to reporting information on JVMs for which it has the access permissions. jinfo &#xff08;1&#xff09;实时…

UniTask保姆级教程

目录 一、UniTask的简介和安装 https://github.com/Cysharp/UniTask.gitpathsrc/UniTask/Assets/Plugins/UniTask 空载性能测试 二、基础用法详解 三、基础用法扩展 四、进阶 五、VContainer简介 六、VContainer基础实例 方便快速查找 一、UniTask的简介和安装 项目地…

Medium: Where to Define Qualified users in A/B testing?

1. Common AB Testing Setup Issue (Framework) 局限性: unqualified users will also be considered and mess up experimentation results.

【力扣周赛】第 112 场双周赛

文章目录 竞赛链接Q1&#xff1a;7021. 判断通过操作能否让字符串相等 IQ2&#xff1a;7005. 判断通过操作能否让字符串相等 II&#xff08;贪心&#xff09;Q3&#xff1a;2841. 几乎唯一子数组的最大和竞赛时代码——滑动窗口 Q4&#xff1a;8050. 统计一个字符串的 k 子序列…

【设备树笔记整理7】实践操作

1 使用设备树给DM9000网卡_触摸屏指定中断 1.1 修改方法 根据设备节点的compatible属性&#xff0c;在驱动程序中构造/注册 platform_driver&#xff0c;在 platform_driver 的 probe 函数中获得中断资源。 1.2 实验方法 以下是修改好的代码&#xff1a;第6课第1节_网卡_触摸…

SIEM 中不同类型日志监控及分析

安全信息和事件管理&#xff08;SIEM&#xff09;解决方案通过监控来自网络的不同类型的数据来确保组织网络的健康安全状况&#xff0c;日志数据记录设备上发生的每个活动以及整个网络中的应用程序&#xff0c;若要评估网络的安全状况&#xff0c;SIEM 解决方案必须收集和分析不…

C/C++源程序到可执行程序exe的全过程(及汇编和反汇编的区别)

1.C/C源程序到可执行程序exe的全过程&#xff08;及汇编和反汇编的区别&#xff09; 一个现代编译器的主要工作流程如下&#xff1a; 源程序&#xff08;source code&#xff09;→预处理器&#xff08;preprocessor&#xff09;→编译器&#xff08;compiler&#xff09;→汇…

解决uniapp手机真机调试时找不到手机问题

1、检查 USB 调试是否开启 2、检查是否有选择 文件 传输 选项 3、如果上述都做了还找不到&#xff0c;可以看看开发者选项中的【USB设置】&#xff0c;把模式改为 MIDI 模式

ToBeWritten之ATTCK 场景实践

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…