【JVM】(二)深入理解Java类加载机制与双亲委派模型

文章目录

  • 前言
  • 一、类加载过程
    • 1.1 加载(Loading)
    • 1.2 验证(Verification)
    • 1.3 准备(Preparation)
    • 1.4 解析(Resolution)
    • 1.5 初始化(Initialization)
  • 二、双亲委派模型
    • 2.1 类加载器
    • 2.2 什么是双亲委派模型
    • 2.3 双亲委派模型的解决的问题
    • 2.4 破坏双亲委派模型


前言

在 Java 中,类加载机制是 Java 虚拟机(JVM)的一个重要组成部分,它负责在运行时将 Java 类加载到内存中,并转换为可执行代码。理解类加载机制对于深入理解 Java 的运行机制和开发高质量的Java应用程序至关重要。

本文将深入探讨 Java 的类加载过程以及双亲委派模型。首先,我将详细介绍类加载过程的五个阶段。接下来,将重点介绍双亲委派模型以及它解决的问题。

一、类加载过程

1.1 加载(Loading)

加载是类加载的第一个阶段。在这个阶段,JVM 会根据类的全限定名(Fully Qualified Name)找到对应的字节码文件,并将其加载到内存中。加载阶段不仅仅包括从文件系统中读取字节码,还可能包括从网络、数据库等地方加载类的字节码。

详细说来,类的加载阶段需要完成三个任务:

  1. 获取字节流
    Java虚拟机根据类的全限定名(Fully Qualified Name)来获取定义该类的二进制字节流。这个过程可以通过从本地文件系统、网络、JAR包等位置读取类的字节码文件,并将其存储在内存中。

  2. 转化为运行时数据结构
    在获取类的字节流后,Java虚拟机将这个字节流所代表的静态存储结构(如类、字段、方法、常量池等)转化为方法区的运行时数据结构。这个过程包括解析字节码中的各种信息,并生成对应的运行时数据结构,用于在运行时执行类的各种操作。

  3. 生成java.lang.Class对象
    在内存中生成一个代表这个类的java.lang.Class对象。这个Class对象是在JVM中表示类的元数据信息的对象,通过这个对象可以访问类的方法、字段、构造函数等信息,以及执行类的各种操作。这个Class对象也是Java程序中获取类的入口,通过它可以访问类的各种静态和动态信息。

注意“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段,它和类加载 (Class Loading) 是不同的,一个是加载 (Loading)另一个是类加载 (Class Loading),不要把二者混淆。

1.2 验证(Verification)

验证是类加载过程的第二个阶段。在验证阶段,JVM 会对加载的字节码进行验证,确保字节码的结构是合法的、符合规范的,不包含安全漏洞和不符合 JVM 规范的内容。这个阶段是确保类加载过程的安全性和正确性的重要步骤

下图是 Java 虚拟机规范中的 Class 文件的结构定义,同时也是验证阶段所需要验证的:

1.3 准备(Preparation)

准备是类加载过程的第三个阶段。在准备阶段,JVM会为类的静态变量分配内存,并设置初始值(通常是零值)这里并不包括对静态变量赋值的操作,赋值的操作将在初始化阶段进行

例如有这样一段代码:

public static int value = 100;

在准备阶段,JVM 会给静态变量 value 分配内存,但是设置的初值是 0,而不是 100,因为赋值操作是在初始化阶段完成的。

1.4 解析(Resolution)

解析是类加载过程的第四个阶段。在解析阶段,JVM 会将符号引用替换为直接引用

  • 符号引用是一种在编译期产生的,用于描述类、字段、方法等的引用
  • 直接引用是指直接指向内存中的地址的引用

解析阶段的目的是将符号引用解析成直接引用,以便在之后的程序执行中更快速地定位到所引用的目标

1.5 初始化(Initialization)

初始化是类加载过程的最后一个阶段。在初始化阶段,JVM会执行类的初始化代码,包括对静态变量赋值执行静态初始化块。类的初始化是在首次使用类的时候触发的,只有在初始化完成后,类才算是被真正加载和准备好了。

二、双亲委派模型

2.1 类加载器

一提到 JVM 的类加载机制,不由自主的就会想到 双亲委派模型,而要理解这个模型,首先就需要了解类加载器。

在 JVM 中,默认有三种类加载器:

  1. 启动类加载器(Bootstrap Class Loader)

    • 这是JVM内部实现的特殊类加载器,由 C++ 编写,而不是 Java 类
    • 负责加载 JVM 自身需要的类,包括核心类库(如java.lang包中的类)等;
    • 启动类加载器是类加载器层次结构的最顶层,没有父加载器
    • 由于其是C++编写的,因此在Java代码中无法直接引用它。
  2. 扩展类加载器(Extension Class Loader)

  • 扩展类加载器是 Java 类,由sun.misc.Launcher$ExtClassLoader实现;
  • 负责加载 JRE(Java Runtime Environment)的扩展目录 lib/ext中的类
  • 扩展类加载器启动类加载器子加载器
  • 同时也是类加载器层次结构中的中间层。
  1. 应用程序类加载器(Application Class Loader)
  • 应用程序类加载器也是 Java 类,由sun.misc.Launcher$AppClassLoader实现;
  • 负责加载应用程序 classpath下的类,即我们自己编写的 Java 类
  • 应用程序类加载器扩展类加载器子加载器
  • 同时处于类加载器层次结构中的最底层。

以上三种类加载器构造了 JVM 的类加载器层次结构,即双亲委派模型。除了启动类加载器是由 C++ 语言实现外,其他的所有加载器均由 Java 实现,并且都继承了java.lang.ClassLoader

下图展示了 JVM 的类加载器的层次结构:

当然,除了默认的这三个类加载器外,开发人员还可以根据自己的需求实现自定义的类加载器。自定义类加载器需要继承自java.lang.ClassLoader,通过重写findClass方法来实现特定的类加载逻辑。自定义的类加载器常用于实现插件机制,热部署等功能。

2.2 什么是双亲委派模型

双亲委派模型是 Java 类加载器的一种类加载机制,简单来说,核心思想就是:一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。

双亲委派模型的类加载过程大致如下图所示:

  • 当一个类加载器收到加载请求的时候(子加载器),它首先会把这个加载请求委派给其父加载器,父加载器可能会继续委托给其父加载器,依次递归。
  • 到达类加载器层次结构的最顶层(启动类加载器)后,再尝试进行类加载。
  • 如果当前加载器无法加载时,就会将加载任务交给其子加载器,由子加载器尝试进行类加载

2.3 双亲委派模型的解决的问题

双亲委派模型主要解决了两个问题:

  1. 类的隔离和防止冲突
  • 在复杂的 Java 应用程序中,可能会涉及许多不同的类库和模块。这些类库和模块可能引用了相同的类名,如果不加以限制,可能就会导致类名冲突
  • 双亲委派模型通过层级结构的类加载器,确保每个类加载器都将加载任务优先委派给父加载器进行加载,这样同名的类只会被加载一次,并且加载过程是有序的,避免了类的冲突和混淆

举个例子:

  • 假设应用程序的类加载器需要加载 java.lang.String 类。
  • 它首先会委派给扩展类加载器,扩展类加载器也找不到,再委派给启动类加载器。因为启动类加载器能够找到并加载 java.lang.String 类,所以它会将该类返回给应用程序类加载器。
  • 由于类加载器的委派顺序,即便应用程序中有自定义java.lang.String 类,也不会被加载,从而保证了类的隔离和防止冲突。
  1. 安全性和可信任代码的执行

Java中的核心类库位于JVM内部,它们提供了Java编程语言的基本功能。这些核心类库在 JVM 启动时由启动类加载器加载。通过双亲委派模型,可以确保核心类库只会被启动类加载器加载,而不会被应用程序类加载器或其他自定义类加载器加载

这种安排提高了Java程序的安全性,因为核心类库的来源可信,不会被恶意类替代。如果允许应用程序类加载器直接加载核心类库,那么恶意类可能会替代核心类库中的某些类,从而导致安全漏洞。双亲委派模型通过限制核心类库的加载,确保了可信任代码的执行,并防止恶意类的篡改

2.4 破坏双亲委派模型

尽管双亲委派模型在大多数情况下是有益的,但是有些特定的场景下就需要破坏它,其中 JDBC 就是一个典型的例子

  • 在 JDBC 中,数据库厂商提供的自己的 JDBC 驱动,这些驱动实现了 JDBC 标准接口的类库。由于 JDBC 驱动需要和特定的数据库交互,因此它们通常由数据库厂商提供,而不是 Java 标准的一部分。而数据库厂商非常多,因此 JDBC 驱动的种类也就非常多了。

  • 考虑到这种情况,JDBC 驱动就需要被应用程序自己加载,而不是委托给父类。如果此时还是按照双亲委派模型的规则进行类加载,那么加载的就是 Java 提供的 JDBC 标准接口的类库中的类了,而不是特定数据库的类。

  • 为了解决这个问题,JDBC 驱动的加载通常是通过反射来实现的应用程序类加载器可以直接加载驱动的类,而不通过双亲委派模型。这样应用程序可以加载自己所需的特定驱动类,而不受父类加载器的限制

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

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

相关文章

数字化采购:提升效率、优化供应链的新趋势

随着信息技术的快速发展,数字化采购正成为企业追求效率和优化供应链的新趋势。数字化采购是利用数字技术和互联网平台,实现采购流程的自动化和在线化。本文将围绕数字化采购的应用场景,探讨其在采购环节中带来的效益与优势。 一、在线供应商…

分布式限流方案及实现

优质博文:IT-BLOG-CN 一、限流的作用和意义 限流是对高并发访问进行限制,限速的过程。通过限流来限制资源,可以提高系统的稳定性和可靠性,控制系统的负载,削峰填谷,保证服务质量。 服务限流后的常见处理…

重磅!EBImage包:为何如此火爆?它的图像处理到底有何不可思议之处?

一、简介 1.1 EBImage包简介 EBImage包是一个广受欢迎的用于图像处理和分析的R语言包。它提供了一套全面而强大的功能,支持多种图像格式的读取和写入,处理多维图像数据,并提供了各种先进的图像处理算法、特征提取和测量函数。 1.2 EBImage爆火…

DAY1,C高级(命令,Linux的文件系统,软、硬链接文件)

1.创建链接文件; 文件系统中的每个文件都与唯一的 inode 相关联,inode 存储了文件的元数据和数据块的地址,文件名与 inode 之间的链接关系称为硬链接或软链接。 硬链接文件的创建: ln 被链接文件的绝对路径 硬链接文件的绝对…

nsqd的架构及源码分析

文章目录 一 nsq的整体代码结构 二 回顾nsq的整体架构图 三 nsqd进程的作用 四 nsqd启动流程的源码分析 五 本篇博客总结 在博客 nsq整体架构及各个部件作用详解_YZF_Kevin的博客-CSDN博客 中我们讲了nsq的整体框架,各个部件的大致作用。如果没看过的&…

论文笔记——Influence Maximization in Undirected Networks

Influence Maximization in Undirected Networks ContributionMotivationPreliminariesNotations Main resultsReduction to Balanced Optimal InstancesProving Theorem 3.1 for Balanced Optimal Instances Contribution 好久没发paper笔记了,这篇比较偏理论&…

pytorch 中 view 和reshape的区别

在 PyTorch(一个流行的深度学习框架)中, reshape 和 view 都是用于改变张量(tensor)形状的方法,但它们在实现方式和使用上有一些区别。下面是它们之间的主要区别: 实现方式: reshap…

html学习7(iframe)

1、通过使用iframe标签定义框架,可在同一个浏览器中显示不止一个画面。 2、height和width属性用于定义框架的高度与宽度。 3、属性frameborder‘0’用于是否显示边框。 4、iframe可以显示一个目标链接的页面,链接的target属性设置为相应的iframe名称。…

2023年华数杯C题思路

c题 母亲身心健康对婴儿成长的影响 母亲是婴儿生命中最重要的人之一,她不仅为婴儿提供营养物质和身体保护,还为婴儿提供情感支持和安全感。母亲心理健康状态的不良状况,如抑郁、焦虑压力等,可能会对婴儿的认知、情感、社会行为等方面产生负面影响。压力…

2023年华数杯C题详细思路

2023年华数杯作为与国赛同频的比赛(都是周四6点发题,周日晚8点交卷),也是暑期唯一一个正式比赛。今年的报名队伍已经高达6000多对。基于这么多的人数进行国赛前队伍的练习,以及其他用途。为了方便大家跟更好的选题&…

机器学习03-数据理解(小白快速理解分析Pima Indians数据集)

机器学习数据理解是指对数据集进行详细的分析和探索,以了解数据的结构、特征、分布和质量。数据理解是进行机器学习项目的重要第一步,它有助于我们对数据的基本属性有全面的了解,并为后续的数据预处理、特征工程和模型选择提供指导。 数据理解…

vue 图片回显标签

第一种 <el-form-item label"打款银行回单"><image-preview :src"form.bankreceiptUrl" :width"120" :height"120"/></el-form-item>// 值为 https://t11.baidu.com/it/app106&fJPEG&fm30&fmtauto&…

SpringBoot整合Caffeine

一、Caffeine介绍 1、缓存介绍 缓存(Cache)在代码世界中无处不在。从底层的CPU多级缓存&#xff0c;到客户端的页面缓存&#xff0c;处处都存在着缓存的身影。缓存从本质上来说&#xff0c;是一种空间换时间的手段&#xff0c;通过对数据进行一定的空间安排&#xff0c;使得下…

如何使用免费敏捷工具Leangoo领歌管理Sprint Backlog

什么是Sprint Backlog&#xff1f; Sprint Backlog是Scrum的主要工件之一。在Scrum中&#xff0c;团队按照迭代的方式工作&#xff0c;每个迭代称为一个Sprint。在Sprint开始之前&#xff0c;PO会准备好产品Backlog&#xff0c;准备好的产品Backlog应该是经过梳理、估算和优先…

JVM调优工具详解以及实战

准备 事先启动一个web应用程序&#xff0c;用jps查看进程id&#xff0c;接着用各种jdk自带的命令优化应用 Jmap jmap -histo 6160 #查看历史生成的实例 jmap -histo:live 6160 #查看当前存活的实例&#xff0c;执行过程中可能会触发一次full gc jmap -histo:live 6160 &…

Chapter 11: Tuples | Python for Everybody 讲义笔记_En

文章目录 Python for Everybody课程简介TuplesTuples are immutableComparing tuplesTuple assignmentDictionaries and tuplesMultiple assignment with dictionariesThe most common wordsUsing tuples as keys in dictionariesSequences: strings, lists, and tuples - Oh M…

FTP文件传输协议

FTP文件传输协议 介绍 将某台计算机中的文件通过网络传送到可能相距很远的另一台计算机中&#xff0c;是一项基本的网络应用&#xff0c;即文件传送文件传输协议(File Transfer Protocol)是因特网上使用得最广泛的文件传输协议 FTP提供交互式访问&#xff0c;允许客户指明文件…

frida学习及使用

文章目录 安装frida安装python3.7设置环境变量安装pycharm和nodejs 使用frida将frida-server push到手机设备中端口转发安装apk使用jadx查看java代码运行frida-server frida源码阅读frida hook方法Frida Java层hoookJavaHook.javaJavaHook.js Frida native层hook 一NativeHook.…

YOLOv5:使用7.0版本训练自己的实例分割模型(车辆、行人、路标、车道线等实例分割)

YOLOv5&#xff1a;使用7.0版本训练自己的实例分割模型&#xff08;车辆、行人、路标、车道线等实例分割&#xff09; 前言前提条件相关介绍使用YOLOv5-7.0版本训练自己的实例分割模型YOLOv5项目官方源地址下载yolov5-7.0版源码解压目录结构 准备实例分割数据集在./data目录下&…

xlrd与xlwt操作Excel文件详解

Python操作Excel的模块有很多&#xff0c;并且各有优劣&#xff0c;不同模块支持的操作和文件类型也有不同。下面是各个模块的支持情况&#xff1a; .xls.xlsx获取文件内容写入数据修改文件内容保存样式调整插入图片xlrd√√√xlwt√√√√√xlutils√√√√xlwings√√√√√…