【实战JVM】-基础篇-02-类的声明周期-加载器

news2024/11/19 5:56:37

【实战JVM】-基础篇-02-类的声明周期-加载器

  • 3 类的生命周期
    • 3.1 生命周期的概述
    • 3.2 加载阶段
      • 3.2.1 查看内存中的对象
    • 3.3 连接阶段
      • 3.3.1 验证阶段
        • 3.3.1.1 验证是否符合jvm规范
        • 3.3.1.2 元信息验证
        • 3.3.1.3 验证语义
        • 3.3.1.4 符号引用验证
      • 3.3.2 准备阶段
      • 3.3.3 解析阶段
    • 3.4 初始化阶段
      • 3.4.1 笔试题
      • 3.4.2 特殊情况
    • 3.5 总结
  • 4 类的加载器
    • 4.1 类加载器的分类
      • 4.1.1 JDK8之前的分类
      • 4.1.2 使用Arthas查看类加载器-classloader
      • 4.1.3 C++启动类加载器BootstrapClassLoader
      • 4.1.4 Java中默认类加载器
        • 4.1.4.1 扩展类加载器ExtClassLoader
        • 4.1.4.2 应用程序类加载器 AppClassLoader
        • 4.1.4.3 Arthas-classloader高级用法
    • 4.2 类加载器的双亲委派机制
      • 4.2.1 Arthas查看类加载器父子关系
      • 4.2.2 面试
    • 4.3 打破双亲委派机制
      • 4.3.1 自定义类加载器
        • 4.3.1.1 Arthas展示类的详细信息
        • 4.3.1.2 正确的自定义类加载器
      • 4.3.2 线程上下文类加载器
        • 4.3.2.1 SPI机制
        • 4.3.2.2 总结
      • 4.3.3 热部署
        • 4.3.3.1 热更新注意事项
    • 4.4 JDK8之后的类加载器


3 类的生命周期

3.1 生命周期的概述

在这里插入图片描述

3.2 加载阶段

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.2.1 查看内存中的对象

推荐使用JDK自带的hsdb工具查看Java虚拟机内部的内存信息。工具位于JDK安装目录下的lib文件夹的sa-jdi.jar中。

启动jvm项目的HsdbDemo

在这里插入图片描述

使用jps展示当前所有的java进程及id

jps

在这里插入图片描述

启动命令

D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\lib>java -cp sa-jdi.jar sun.jvm.hotspot.HSDB

在这里插入图片描述

输入我们要找的类的编号HsdbDemo:18648

在这里插入图片描述

直接搜索HsdbDemo,因为我们只new了一次,自然只有一个对象。

在这里插入图片描述

在这里插入图片描述

一句话概括:类加载器将类的信息加载到内存中,java虚拟机在方法区和堆区中各分配一个对象去保存这个信息,而我们需要操作的则是堆区中的对象,jdk8之后静态字段也是存在堆中的

3.3 连接阶段

在这里插入图片描述

3.3.1 验证阶段

3.3.1.1 验证是否符合jvm规范

在这里插入图片描述

3.3.1.2 元信息验证

在这里插入图片描述

3.3.1.3 验证语义

在这里插入图片描述

3.3.1.4 符号引用验证

判断是否访问了其他类的private方法。

3.3.2 准备阶段

在这里插入图片描述
value在准备阶段分配的值是默认值0,而赋值为1是初始化阶段做的事

在这里插入图片描述

但是也有例外,如果是final修饰的基本数据类型,会在准备阶段直接将代码中的值进行赋值。

public static final int value=1;

3.3.3 解析阶段

在这里插入图片描述

直接引用不在使用编号,而是直接使用内存中的地址进行访问具体的数据。

3.4 初始化阶段

  • 初始化阶段会执行静态代码中的代码,并为静态变量赋值
  • 初始化阶段会执行字节码文件中的clinit部分的字节码指令。

在这里插入图片描述

如果颠倒一下顺序,那么输出则是1

在这里插入图片描述

因为静态变量是在连接阶段准备阶段完成默认初始化。然后再赋为2,再赋为1。

在这里插入图片描述

3.4.1 笔试题

(1)

在这里插入图片描述

构造代码块先于构造方法前执行

3.4.2 特殊情况

在这里插入图片描述

  • 直接访问父类的静态变量,不会触发子类的初始化。

  • 子类的初始化clinit调用之前,会先调用父类的clinit初始化方法。
    在这里插入图片描述

  • 数组的创建不会导致数组中元素的类进行初始化。

    • 是因为创建数组时是创建的数组的对象,而不是数组中元素的对象。所以数组中元素的类不会进行初始化。
  • 如果一个变量用final修饰,并且其中的内容要执行指令才能得出结果,那么会在clinit方法中进行初始化。

3.5 总结

在这里插入图片描述

4 类的加载器

类加载器是jvm提供给应用程序去实现获取类和接口字节码数据的技术。

负责在类加载过程中的字节码获取并且加载到内存这一部分。通过加载字节码数据放入内存转换成byte[],接下来调用虚拟机底层的方法将byte[]转换成方法区和堆中的数据。

4.1 类加载器的分类

在这里插入图片描述

俩下Shift是搜索
Ctrl+Alt+类是找当前类的所有实现

4.1.1 JDK8之前的分类

在这里插入图片描述

  • 引导类加载器 Bootstrap,加载属于JVM的一部分,由C++代码实现,负责加载<JAVA_HOME\>\jre\lib路径下的核心类库
  • 扩展类加载器 ExtClassLoader,扩展类加载器负责加载<JAVA_HOME>\jre\lib\ext目录下的类库。
  • 应用程序类加载器 AppClassLoader,应用程序类加载器负责加载 classpath环境变量所指定的类库,是用户自定义类的默认类加载器。

4.1.2 使用Arthas查看类加载器-classloader

在这里插入图片描述

启动Hsdbdemo后打开arthas,在arthas工作目录中启动

java -jar arthas-boot.jar

进入Hsdbdemo

classloader

在这里插入图片描述

4.1.3 C++启动类加载器BootstrapClassLoader

负责加载<JAVA_HOME\>\jre\lib路径下的核心类库

通过类名.class.getClassLoader来获取当前类的类加载器。

在这里插入图片描述

添加java虚拟机参数D:/jvm/jar/classloader-test.jar是jar包地址

-Xbootclasspath/a:D:/jvm/jar/classloader-test.jar

4.1.4 Java中默认类加载器

在这里插入图片描述

4.1.4.1 扩展类加载器ExtClassLoader

扩展类加载器 ExtClassLoader,扩展类加载器负责加载<JAVA_HOME>\jre\lib\ext目录下的类库。

在这里插入图片描述

添加java虚拟机参数D:/jvm/jar/classloader-test.jar是jar包地址。

不仅需要jar包的地址,还需要原来ext的地址D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\jre\lib\ext

-Djava.ext.dirs="D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\jre\lib\ext;D:/jvm/jar/classloader-test.jar"

在windows中;是追加,linux和mac中:是追加,尽量用双引号引起俩,以免因为特殊字符报错。

4.1.4.2 应用程序类加载器 AppClassLoader

应用程序类加载器 AppClassLoader,应用程序类加载器负责加载 classpath环境变量所指定的类库,是用户自定义类的默认类加载器。既可以加载当前项目中创建的类,也可以加载maven依赖中包含的类。

4.1.4.3 Arthas-classloader高级用法
classloader -l

在这里插入图片描述

查看当前所有的类加载器以及其哈希值

classloader -c hash值

在这里插入图片描述

查看当前查询的类加载器加载的所有jar包

在这里插入图片描述

4.2 类加载器的双亲委派机制

jvm中有多个类加载器,双亲委派机制的核心就是解决一个类到底由谁加载的问题。

双亲委派机制的作用

  1. 保证类加载的安全性

    通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如Java.lang.String,确保核心类库的完整性和安全性。

  2. 避免重复加载

    双亲委派机制可以避免同一个类被多次加载

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.2.1 Arthas查看类加载器父子关系

classloader -t

在这里插入图片描述

4.2.2 面试

在这里插入图片描述

4.3 打破双亲委派机制

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.3.1 自定义类加载器

在这里插入图片描述

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
    if(name.startsWith("java.")){
        return super.loadClass(name);
    }
    byte[] data = loadClassData(name);
    return defineClass(name, data, 0, data.length);
}

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
    BreakClassLoader1 classLoader1 = new BreakClassLoader1();
    classLoader1.setBasePath("D:\\lib\\");
    Class<?> clazz1 = classLoader1.loadClass("com.itheima.my.A");
    BreakClassLoader1 classLoader2 = new BreakClassLoader1();
    classLoader2.setBasePath("D:\\lib\\");
    Class<?> clazz2 = classLoader2.loadClass("com.itheima.my.A");
    System.out.println(clazz1 == clazz2);
    Thread.currentThread().setContextClassLoader(classLoader1);
    System.out.println(Thread.currentThread().getContextClassLoader());
    System.in.read();
 }

重写loadClass方法,删除双亲委派机制,如果是java开头的jar包,就交给原先父类的loadClass,如果是自定义的,就自己直接加载。

自定义类加载器没指定双亲的话,默认双亲为应用程序类加载器

在这里插入图片描述

4.3.1.1 Arthas展示类的详细信息
sc -d com.itheima.my.A

在这里插入图片描述

因为刚刚用两个不同的类加载器加载com.itheima.my.A,自然得到两个不同的对象

4.3.1.2 正确的自定义类加载器

在这里插入图片描述

4.3.2 线程上下文类加载器

在这里插入图片描述

DriverManager类位于rt.jar包中,由启动类加载器加载。

在这里插入图片描述

4.3.2.1 SPI机制

SPI全程Service Provider Interface,是JDK内置的一种服务提供发现的机制

需要在resources目录下新建META-INF/services目录,并且在这个目录下新建一个与上述接口的全限定名一致的文件java.sql.Driver的接口,在这个文件中写入接口的实现类的全限定名com.mysql.cj.jdbc.Driver。

在这里插入图片描述

ServiceLoader这个类的源码如下:

public final class ServiceLoader<S> implements Iterable<S> {
    //扫描目录前缀
    private static final String PREFIX = "META-INF/services/";
    // 被加载的类或接口
    private final Class<S> service;
    // 用于定位、加载和实例化实现方实现的类的类加载器
    private final ClassLoader loader;
    // 上下文对象
    private final AccessControlContext acc;
    // 按照实例化的顺序缓存已经实例化的类
    private LinkedHashMap<String, S> providers = new LinkedHashMap<>();
    // 懒查找迭代器
    private java.util.ServiceLoader.LazyIterator lookupIterator;
    // 私有内部类,提供对所有的service的类的加载与实例化
    private class LazyIterator implements Iterator<S> {
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        String nextName = null;
        //...
        private boolean hasNextService() {
            if (configs == null) {
                try {
                    //获取目录下所有的类
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    //...
                }
                //....
            }
        }
        private S nextService() {
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                //反射加载类
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
            }
            try {
                //实例化
                S p = service.cast(c.newInstance());
                //放进缓存
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                //..
            }
            //..
        }
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在线程中使用

Thread.currentThread().getContextClassLoader()

默认获得的是应用程序类加载器

4.3.2.2 总结

在这里插入图片描述

在这里插入图片描述

所以说,打破双亲委派机制的唯一方法就是重写loadClass或者findClass方法

4.3.3 热部署

在这里插入图片描述

  1. 启动SpringbootClassfileApplication后,使用arthas进入,反编译出UserController

    java -Dfile.encoding=UTF-8 -jar arthas-boot.jar
    
    jad --source-only com.itheima.springbootclassfile.controller.UserController > "D:\Code\JavaCode\JVM\hot-replace\UserController.java"
    

在这里插入图片描述

修改为

if (type.equals(UserType.REGULAR.getType())) {
  1. 编译成字节码文件,如果直接编译,则会因为找不到类加载器而报错,所以需要先找到UserController.java的类加载器,获取其哈希值。

    sc -d com.itheima.springbootclassfile.controller.UserController
    

    在这里插入图片描述

  2. mc -c指定类加载器的哈希码 -d指定输出目录

    mc -c 18b4aac2 "D:\Code\JavaCode\JVM\hot-replace\UserController.java" -d "D:\Code\JavaCode\JVM\hot-replace"
    

    在这里插入图片描述

  3. 通过retransform

    retransform "D:\Code\JavaCode\JVM\hot-replace\com\itheima\springbootclassfile\controller\UserController.class"
    

    在这里插入图片描述

  4. 用jad查看热部署是否完成

    在这里插入图片描述

  5. 发送http请求

    在这里插入图片描述

    说明热部署已经完成

4.3.3.1 热更新注意事项

在这里插入图片描述

4.4 JDK8之后的类加载器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

应用类加载器和扩展类加载器都是继承关系从URLClassLoader变为BuiltinClassLoader,没有太大的区别。

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

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

相关文章

从一个时间序列数据中生成一个Markov Transition Field (MTF)

Markov Transition Field&#xff08;马尔科夫转移场&#xff0c;简称MTF&#xff09;是一个用来表示时间序列数据中不同时间点之间状态转移概率的可视化工具。简单来说&#xff0c;它展示了一个时间点上的状态如何可能转移到另一个时间点的状态&#xff0c;这些转移概率是通过…

C语言指针相关知识(第五篇章)(非常详细版)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、sizeof和strlen对比二、数组之间的比较&#xff08;依据strlen和sizeof来呈现&#xff09;&#xff08;一&#xff09;、一维整型数组&#xff08;二&#…

着急联系媒体投稿发表文章有什么好方法?

作为一名曾经的信息宣传员,我深知在紧张的宣传节点上,急于将精心撰写的文章推向更广阔的读者群体,那种紧迫感和焦虑几乎成了常态。记得那段时间,为了能让稿件得到及时有效的曝光,我不得不亲自踏上了一场寻找媒体联系方式的“马拉松”。那时,我手头的资源有限,仅有的几个联系方式…

学 Java 具体能干什么?

学习 Java 后&#xff0c;你可以从事许多不同的工作和项目&#xff0c;涵盖了广泛的应用领域。以下是一些具体的应用场景和工作方向&#xff1a; 1. 企业级应用开发 Java 是企业级应用开发的首选语言之一&#xff0c;特别适合开发大规模、分布式、多层次的企业应用程序。 Jav…

创建列表的艺术:三种实用方法全解析

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、基础篇&#xff1a;直接使用中括号创建列表 1. 创建空列表 2. 创建包含元素的列表 二…

【经典文献】光-声立体成像:关于系统标定与三维目标重建

论文名称&#xff1a;《Opti-Acoustic Stereo Imaging: On System Calibration and 3-D Target Reconstruction》作者列表&#xff1a;Shahriar Negahdaripour, Hicham Sekkati, and Hamed Pirsiavash作者单位&#xff1a;美国迈阿密大学电气与计算机工程系&#xff0c;佛罗里达…

sourcetree推送到git上面

官网&#xff1a;Sourcetree | Free Git GUI for Mac and Windows 下载到1次提交 下载后打开 点击跳过 下一步 名字邮箱 点击clone 把自己要上传的代码粘贴到里面去 返回点击远程->点击暂存所有 加载完毕后&#xff0c;输入提交内容提交 提交完成了 2次提交 把文件夹内的…

iOS 17.5 release notes

文章目录 iOS 17.5 更新恢复了多年前删除的一些图片新增彩虹壁纸欧盟用户可直接从网站下载应用新增了追踪通知改进 Apple News图书应用"阅读目标"设计更新颜色匹配的播客小部件Web浏览器安全权限的访问下一代“Beats Pill”扬声器在iOS 17.5代码中得到确认店内Vision…

面试被问到不懂的东西,是直接说不懂还是坚持狡辩一下?

大家好&#xff0c;我是瑶琴呀。 面试被问到不懂的东西&#xff0c;是直接说不懂还是坚持狡辩一下&#xff1f;这个问题可以转变一下&#xff0c;如果你顺利拿到 offer&#xff0c;公司安排的工作跟你之前的技术和经验不匹配&#xff0c;你还愿意干下去吗&#xff1f; 转变一…

基于Vue+SpirngBoot的博客管理平台的设计与实现(论文+源码)_kaic

摘 要 随着当下社会的发展&#xff0c;互联网已经成为时代的主流&#xff0c;从此进入了互联网时代&#xff0c;对大部分人来说&#xff0c;互联网在日常生活中的应用是越来越频繁&#xff0c;大家都在互联网当中互相交流、学习、娱乐。博客正是扮演这样一个角色。博客已成为当…

Docker 安装kingbase V8r6

下载 官网下载&#xff0c;注意&#xff1a;这里下载 Docker 版本v8r6 安装 # 导入镜像 docker load -i kingbase.tar# 重命名 docker tag [image-name]:[tag] [new-image-name]:[new-tag]# 删除 docker rmi [image-name]:[tag]# 创建容器 docker run -tid \ --privileged \…

计算机毕业设计 | SpringBoot招投标 任务发布网站(附源码)

1&#xff0c;绪论 在市场范围内&#xff0c;任务发布网站很受欢迎&#xff0c;有很多开发者以及其他领域的牛人&#xff0c;更倾向于选择工作时间、工作场景更自由的零工市场寻求零散单子来补贴家用。 如今市场上&#xff0c;任务发布网站鱼龙混杂&#xff0c;用户需要找一个…

使用大模型结合Mermaid实现业务流程图快速生成

一、需求描述 在日常系统研发过程中&#xff0c;经常面临前期要写投标技术文档&#xff0c;中期要写系统概要设计、详细设计等各类文档&#xff0c;最耗时间的便是画一些业务流程图。随着大模型的不断普及&#xff0c;大模型对文字的处理越来越强&#xff0c;现可以找一个能简化…

pycharm连接阿里云服务器过程记录

因为不想用自己的电脑安装anaconda环境,所以去查了一下怎么用服务器跑代码,试着用pycharm连接阿里云服务器,参考了很多博客,自己简单配置了一下,记录一下目前完成的流程. 主要是:阿里云服务器的远程登录和安装anaconda,以及怎么用pycharm连接阿里云服务器上的解释器. 小白刚开始…

Python 渗透测试:电子邮件 || Redis || FTP || SSH || MySQL 集成爆破工具.

集成爆破工具. 集合爆破里面包含了&#xff1a;电子邮件爆破工具&#xff0c;Redis爆破工具&#xff0c;FTP爆破工具&#xff0c;SSH爆破工具&#xff0c;MySQL爆破工具。 目录&#xff1a; 集合爆破工具. 电子邮件 爆破工具&#xff1a; Redis 爆破工具&#xff1a; FTP …

元组推导式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 使用元组推导式可以快速生成一个元组&#xff0c;它的表现形式和列表推导式类似&#xff0c;只是将列表推导式中的“[]”修改为“()”。例如&#xf…

Quartus Cyclone I II III IVE 器件型号

玩耍了一个 EP2 型号的开发板&#xff0c;发现 安装的quartus13 没有Cyclone II 型号&#xff0c;经过探索发现了是版本不对。 https://www.intel.com/content/www/us/en/software-kit/711920/intel-quartus-ii-subscription-edition-design-software-version-13-0sp1-for-win…

java欢迪迈手机商城设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的欢迪迈手机商城设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 欢迪迈手机商城…

【JVM】内存区域划分 | 类加载的过程 | 双亲委派机制 | 垃圾回收机制

文章目录 JVM一、内存区域划分1.方法区&#xff08;1.7之前&#xff09;/ 元数据区&#xff08;1.8开始&#xff09;2.堆3.栈4.程序计数器常见面试题&#xff1a; 二、类加载的过程1.类加载的基本流程1.加载2.验证3.准备4.解析5.初始化 2.双亲委派模型类加载器找.class文件的过…

智能无网远控再升级 向日葵Q2Pro升级版发布

无网或者内网设备也想要进行远程控制&#xff0c;是不是听上去有些天方夜谭了&#xff1f;其实这类特种设备的远程控制需求是非常强的&#xff0c;比如医疗/工控设备的远程运维、使用指导教学等等。 实际上&#xff0c;只要这类设备有屏幕&#xff0c;支持可视化的桌面操作&am…