JVM- 第二章-类加载子系统

news2025/1/13 10:06:17

类加载子系统

  • 2. 类加载子系统
    • 2.1. 内存结构概述
    • 2.2. 类加载器与类的加载过程
      • 加载阶段
      • 链接阶段
      • 初始化阶段
    • 2.3. 类加载器分类
      • 2.3.1. 虚拟机自带的加载器
      • 2.3.2. 用户自定义类加载器
    • 2.4. ClassLoader的使用说明
    • 2.5. 双亲委派机制
    • 2.6. 其他

2. 类加载子系统

2.1. 内存结构概述

  • Class文件

  • 类加载子系统

  • 运行时数据区

    • 方法区
    • 程序计数器
    • 虚拟机栈
    • 本地方法栈
  • 执行引擎

  • 本地方法接口

  • 本地方法库

image-20200705080719531

image-20200705080911284

如果自己想手写一个Java虚拟机的话,主要考虑哪些结构呢?

  • 类加载器
  • 执行引擎

2.2. 类加载器与类的加载过程

类加载器子系统作用

image-20200705081813409

  • 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。
  • ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。
  • 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

类加载器ClasLoader角色

image-20200705081913538

  • class file存在于本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM当中来根据这个文件实例化出n个一模一样的实例。
  • class file加载到JVM中,被称为DNA元数据模板,放在方法区。
  • 在.class文件->JVM->最终成为元数据模板,此过程就要一个运输工具(类装载器Class Loader),扮演一个快递员的角色。

类的加载过程

/**
 *示例代码
 */
public class HelloLoader {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

用流程图表示上述示例代码:

image-20200705082255746

加载阶段

image-20200705082601441

    1. 通过一个类的全限定名获取定义此类的二进制字节流
    1. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    1. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

补充:加载class文件的方式

  • 本地系统中直接加载
  • 通过网络获取,典型场景:Web Applet
  • 从zip压缩包中读取,成为日后jar、war格式的基础
  • 运行时计算生成,使用最多的是:动态代理技术
  • 由其他文件生成,典型场景:JSP应用
  • 从专有数据库中提取.class文件,比较少见
  • 加密文件中获取,典型的防Class文件被反编译的保护措施

链接阶段

  • 验证(Verify)

    • 目的在子确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
    • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
  • 准备(Prepare)

    • 为类变量分配内存并且设置该类变量的默认初始值,即零值。
    • 这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化;
    • 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
  • 解析(Resolve)

    • 将常量池内的符号引用转换为直接引用的过程。
    • 事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。
    • 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的Class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
    • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT_Class_info,CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

初始化阶段

  • 初始化阶段就是执行类构造器方法<clinit>()的过程。
  • 此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。
  • 构造器方法中指令按语句在源文件中出现的顺序执行。
  • <clinit>()不同于类的构造器。(关联:构造器是虚拟机视角下的<init>())
  • 若该类具有父类,JVM会保证子类的<clinit>()执行前,父类的<clinit>()已经执行完毕。
  • 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁。

2.3. 类加载器分类

JVM支持两种类型的类加载器 。分别为引导类加载器(Bootstrap ClassLoader)自定义类加载器(User-Defined ClassLoader)

从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器

无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kdQftM0E-1673432204658)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f2a56464d4a44f69615263b50901eff~tplv-k3u1fbpfcp-zoom-1.image)]

这里的四者之间的关系是包含关系。不是上层下层,也不是子父类的继承关系。

2.3.1. 虚拟机自带的加载器

启动类加载器(引导类加载器,Bootstrap ClassLoader)

  • 这个类加载使用C/C++语言实现的,嵌套在JVM内部。
  • 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类
  • 并不继承自ava.lang.ClassLoader,没有父加载器。
  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器。
  • 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

扩展类加载器(Extension ClassLoader)

  • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现。
  • 派生于ClassLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/1ib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

应用程序类加载器(系统类加载器,AppClassLoader)

  • java语言编写,由sun.misc.LaunchersAppClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为扩展类加载器
  • 它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
  • 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载
  • 通过ClassLoader#getSystemclassLoader() 方法可以获取到该类加载器

2.3.2. 用户自定义类加载器

在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。 为什么要自定义类加载器?

  • 隔离加载类
  • 修改类加载的方式
  • 扩展加载源
  • 防止源码泄漏

用户自定义类加载器实现步骤:

  1. 开发人员可以通过继承抽象类ava.lang.ClassLoader类的方式,实现自己的类加载器,以满足一些特殊的需求
  2. 在JDK1.2之前,在自定义类加载器时,总会去继承ClassLoader类并重写loadClass() 方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadclass() 方法,而是建议把自定义的类加载逻辑写在findClass()方法中
  3. 在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass() 方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

2.4. ClassLoader的使用说明

ClassLoader类是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHCjLY6I-1673432204659)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f4e6f4e59fbf4020a5c3a27754665f70~tplv-k3u1fbpfcp-zoom-1.image)]

sun.misc.Launcher 它是一个java虚拟机的入口应用

image-20200705103636003

获取ClassLoader的途径

  • 方式一:获取当前ClassLoader

    clazz.getClassLoader()
    
  • 方式二:获取当前线程上下文的ClassLoader

    Thread.currentThread().getContextClassLoader()
    
  • 方式三:获取系统的ClassLoader

    ClassLoader.getSystemClassLoader()
    
  • 方式四:获取调用者的ClassLoader

    DriverManager.getCallerClassLoader()
    

2.5. 双亲委派机制

Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

工作原理

  • 1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
  • 2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
  • 3)如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

image-20200705105151258

举例

当我们加载jdbc.jar 用于实现数据库连接的时候,首先我们需要知道的是 jdbc.jar是基于SPI接口进行实现的,所以在加载的时候,会进行双亲委派,最终从根加载器中加载 SPI核心类,然后在加载SPI接口类,接着在进行反向委派,通过线程上下文类加载器进行实现类jdbc.jar的加载。

image-20200705105810107

优势

  • 避免类的重复加载

  • 保护程序安全,防止核心API被随意篡改

    • 自定义类:java.lang.String
    • 自定义类:java.lang.ShkStart(报错:阻止创建 java.lang开头的类)

沙箱安全机制

自定义String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的string类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

2.6. 其他

如何判断两个class对象是否相同

在JVM中表示两个class对象是否为同一个类存在两个必要条件:

  • 类的完整类名必须一致,包括包名。
  • 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。

换句话说,在JVM中,即使这两个类对象(class对象)来源同一个Class文件,被同一个虚拟机所加载,但只要加载它们的ClassLoader实例对象不同,那么这两个类对象也是不相等的。

对类加载器的引用

JVM必须知道一个类型是由启动加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JVM需要保证这两个类型的类加载器是相同的。

类的主动使用和被动使用

Java程序对类的使用方式分为:主动使用和被动使用。

主动使用,又分为七种情况:

  • 创建类的实例

  • 访问某个类或接口的静态变量,或者对该静态变量赋值

  • 调用类的静态方法

  • 反射(比如:Class.forName(“com.atguigu.Test”))

  • 初始化一个类的子类

  • Java虚拟机启动时被标明为启动类的类

  • JDK 7 开始提供的动态语言支持:

    java.lang.invoke.MethodHandle实例的解析结果

    REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化

除了以上七种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化

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

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

相关文章

nacos

文章目录1、认识和安装nacos&#xff08;单机安装&#xff09;1.1、下载安装包1.2、解压1.3、端口配置1.4、启动1.5、访问2、nacos快速入门2.1、在父工程中添加依赖2.2、注释掉服务中原有的eureka依赖2.3、添加nacos的客户端依赖2.4、修改配置文件2.5、启动并测试2.6、总结3、n…

19、Java并发 Java wait() 和 notify() 方法

大家有没有发现&#xff0c;其实 「 一文秒懂 」 系列讲述的都是多线程并发开发的问题。这个话题太大了&#xff0c;估计没有上百篇文章都解释不清楚。 本文&#xff0c;我们来讲解下 Java 并发中的基础的基础&#xff0c;核心的核心&#xff0c;Java 并发编程中的最基本的机制…

为什么 APISIX Ingress 是比 Ingress NGINX 更好的选择?

作者容鑫&#xff0c;API7.ai 云原生技术工程师&#xff0c;Apache APISIX Committer。 本文将会对比两个比较流行的 Ingress controller 实现&#xff0c;希望能对读者进行 Ingress controller 选型中有所帮助。 Ingress NGINX 是 Kubernetes 社区实现的 Ingress controller&a…

高通量代谢组学四路筛选法,揭秘“神药”二甲双胍延长寿命的机制

百趣代谢组学分享—研究背景 目前据统计中国糖尿病患者人数达9700万以上&#xff0c;数量达到世界第一。这其中2型糖尿病占到了90%以上。二甲双胍是目前治疗2型糖尿病的一线“明星”药物&#xff0c;因其较少出现低血糖和体重增加副作用而受到广大患者和医生的青睐。代谢组学文…

Replicate Brogaard Stock Volatility Decomposition

文章目录IntroductionData and SampleDownload DataClean DataExtract Estimation Unit and Set Global VariablesImplement Brogaard DecompositionEstimate VAR Coefficients, Matrix BBB, ϵt\epsilon_tϵt​, Σe\Sigma_eΣe​, and Σϵ\Sigma_\epsilonΣϵ​Estimate 15-…

常用的前端大屏 适配方案

方案实现方式优点缺点vm vh1.按照设计稿的尺寸&#xff0c;将px按比例计算转为vw和vh1.可以动态计算图表的宽高&#xff0c;字体等&#xff0c;灵活性较高 2.当屏幕比例跟 ui 稿不一致时&#xff0c;不会出现两边留白情况1.每个图表都需要单独做字体、间距、位移的适配&#xf…

【寒假每日一题】AcWing 4509. 归一化处理

目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 1、cmath头文件相关函数 2、cout大法 一、题目 1、原题链接 4509. 归一化处理 - AcWing题库 2、题目描述 在机器学习中&#xff0c;对数据进行归一化处理…

【C++】list用法简单模拟实现

文章目录1. list的介绍及使用1.1 list基本概念1.2 list的构造1.3 list的迭代器使用1.4 list 赋值和交换1.5 list 插入和删除1.6 list容量大小操作1.7 list 数据存取2. list的模拟实现这次要模拟实现的类及其成员函数接口总览2.1 结点类的实现2.2 迭代器的模拟实现2.3 反向迭代器…

yolov1 论文精读 - You Only Look Once- Unified, Real-Time Object Detection-统一的实时目标检测

Abstract 我们提出了一种新的目标检测方法- YOLO。以前的目标检测工作重复利用分类器来完成检测任务。相反&#xff0c;我们将目标检测框架看作回归问题&#xff0c;从空间上分割边界框和相关的类别概率。单个神经网络在一次评估中直接从整个图像上预测边界框和类别概率。由于…

PDF体积太大怎么缩小?这两种方法轻松解决

在我们日常处理的文件中&#xff0c;PDF文件的体积已经算是比较小的文件了&#xff0c;但是随着工作时间增加&#xff0c;我们用到的PDF文件也越来越多&#xff0c;而且有些PDF文件的内容非常丰富&#xff0c;文件体积变得更大&#xff0c;这就不利于我们将文件传输给别人&…

人脸检测算法模型MTCNN

MTCNN,Multi-task convolutional neural network(多任务卷积神经网络),将人脸区域检测与人脸关键点检测放在了一起。总体可分为P-Net、R-Net、和O-Net三层网络结构。P-Net是快速生成候选窗口,R-Net进行高精度候选窗口的过滤和选择,O-Net是生成最终边界框和人脸关键点。该…

使用JDK的 keytool 生成JKS,修改查看JKS信息

什么是keytool keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书&#xff0c;在JDK 1.4以后的版本中都包含了这一工具&#xff0c;所以不用再上网去找keytool的安装&#xff0c;电脑如果安装有JDK1.4及以上&#xff0c;就可以直接使用。 第一步&…

TOOM舆情分析网络舆情监控平台研究现状

随着网络舆情迅速发展&#xff0c;国内的舆情监测行业也日渐完善&#xff0c;舆情监控平台在企业发展过程中发挥重要作用&#xff0c;但同样也是有问题存在的&#xff0c;接下来TOOM舆情分析网络舆情监控平台研究现状? 一、网络舆情监控平台 网络舆情监控平台是一种能够对网…

maven概述以及简单入门

目录 1、Maven概述 1.1、Maven是什么 1.2 依赖管理 1.3 maven管理资源存放地址 1.4 Maven的作用 2.Maven基础概念 2.1仓库概念 2.坐标概念 1、Maven概述 1.1、Maven是什么 在Javaweb开发中&#xff0c;需要使用大量的jar包&#xff0c;我们手动去导入&#xff1b; 如何…

Mask RCNN网络源码解读(Ⅵ) --- 自定义数据集读取:MS COCOPascal VOC

目录 1.如何在Mask R-CNN中读取有关COCO数据集的内容&#xff08;my_dataset_coco.py&#xff09; 1.1 CocoDetection类 1.1.1 初始化方法__init__ 1.1.2 __getitem__方法 1.1.3 parse_targets 2.如何在Mask R-CNN中读取有关Pascal VOC数据集的内容&#xff08;my_datas…

docker搭建 java web服务

安装 Docker 只需通过以下命令即可安装 Docker 软件&#xff1a; >> rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm >> yum -y install docker-io可使用以下命令&#xff0c;查看 Docker 是否安装成功&#xff1a; …

SpringMvc源码分析(一):启动tomcat服务器,加载DispatcherServlet并将DispatcherServlet纳入tomcat管理

SpringMvc是主流的MVC框架&#xff0c;它是基于Spring提供的web应用框架&#xff0c;该框架遵循servlet规范。该框架的作用是接收Servlet容器&#xff08;如Tomcat&#xff09;传递过来的请求并返回响应。SpringMvc的核心就是servlet实例&#xff0c;而这个servlet在spring中就…

IB地理科SL和HL课程的区别

今期我们会谈到IB地理科这一科目的标准级别&#xff08;StandardLevel&#xff0c;SL&#xff09;课程和高级级别&#xff08;HigherLevel&#xff0c;HL&#xff09;。 两课程的最大区别:试卷数目和题目数量的不同&#xff0c;但两者的教材内容和科目指引&#xff08;SubjectG…

VTK-不同类型的数据集

前言&#xff1a;本博文主要讲解vtk中不同类型的数据集以及它们之间的关系&#xff0c;如何进行转换等。 目录 vtkImageData vtkRectilinearGrid vtkStructuredGrid vtkUnstructuredPoints vtkPolyData vtkUnstructuredGrid vtkPolyData->vtkImageData vtkPolyData…

Go反射学习

文章目录反射介绍&#xff1a;反射应用点变量-空接口-reflect.Value&#xff08;Type)类型值方法结构体&#xff1a;反射修改变量值反射操作结构体MethodCall反射介绍&#xff1a; 反射是在运行时&#xff0c;动态的获取变量的各种信息&#xff0c;如变量的类型&#xff0c;类…