【吊打面试官系列】Java虚拟机JVM篇 - 关于类加载器的JVM面试题

news2024/11/16 21:28:13

大家好,我是锋哥。今天分享关于类加载器的JVM面试题,希望对大家有帮助;

什么是类加载器?

类加载器是一个用来加载类文件的类。Java源代码通过javac编译器编译成类文件。然后JVM来执行类文件中的字节码来执行程序。类加载器负责加载文件系统、网络或其他来源的类文件。
 

类加载器有哪些?

有三种默认使用的类加载器:Bootstrap类加载器、Extension类加载器和Application类加载器。每种类加载器都有设定好从哪里加载类。

  • Bootstrap类加载器负责加载rt.jar中的JDK类文件,它是所有类加载器的父加载器。Bootstrap类加载器没有任何父类加载器,如果你调用String.class.getClassLoader(),会返回null,任何基于此的代码会抛出NullPointerException异常。Bootstrap加载器被称为初始类加载器。
  • 而Extension将加载类的请求先委托给它的父加载器,也就是Bootstrap,如果没有成功加载的话,再从jre/lib/ext目录下或者java.ext.dirs系统属性定义的目录下加载类。Extension加载器由
    sun.misc.LauncherͅExtClassLoader实现。
  • 第三种默认的加载器就是Application类加载器了。它负责从classpath环境变量中加载某些应用相关的类,classpath环境变量通常由-classpath或-cp命令行选项来定义,或者是JAR中的Manifest的classpath属性。Application类加载器是Extension类加载器的子加载器。通过sun.misc.LauncherͅAppClassLoader实现。

1000道 互联网大厂Java工程师 精选面试题-Java资源分享网1000道 互联网大厂Java工程师 精选面试题icon-default.png?t=N7T8http://java.python222.com/article/971

什么是双亲委派模型(Parent-Delegation Model)?

JVM中加载类机制采用的是双亲委派模型,顾名思义,在该模型中,子类加载器收到的加载请求,不会先去处理,而是先把请求委派给父类加载器处理,当父类加载器处理不了时再返回给子类加载器加载;

为什么使用双亲委派模型?

因为安全。使用双亲委派模型来组织类加载器间的关系,能够使类的加载也具有层次关系,这样能够保证核心基础的Java类会被根加载器加载,而不会去加载用户自定义的和基础类库相同名字的类,从而保证系统的有序、安全。

请你描述一下Java中的类加载机制?

Java 虚拟机负责把描述类的数据从 Class 文件加载到系统内存中,并对类的数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这个过程被称之为 Java 的 类加载机制 。一个类从被加载到虚拟机内存开始,到卸载出内存为止,一共会经历下面这些过程。


类加载机制一共有五个步骤,分别是加载、链接、初始化、使用和卸载阶段,这五个阶段的顺序是确定的。


其中链接阶段会细分成三个阶段,分别是验证、准备、解析阶段,这三个阶段的顺序是不确定的,这三个阶段通常交互进行。解析阶段通常会在初始化之后再开始,这是为了支持 Java 语言的运行时绑定特性(也被称为 动态绑定 )。


下面我们就来聊一下这几个过程。

加载

关于什么时候开始加载这个过程,《Java 虚拟机规范》并没有强制约束,所以这一点我们可以自由实现。加载是整个类加载过程的第一个阶段,在这个阶段,Java 虚拟机需要完成三件事情:

  • 通过一个类的全限定名来获取定义此类的二进制字节流。
  • 将这个字节流表示的一种存储结构转换为运行时数据区中方法区的数据结构。
  • 在内存中生成一个 Class 对象,这个对象就代表了这个数据结构的访问入口。

《Java 虚拟机规范》并未规定全限定名是如何获取的,所以现在业界有很多获取全限定名的方式:

  • 从 ZIP 包中读取,最终会改变为 JAR、EAR、WAR 格式。
  • 从网络中获取,最常见的应用就是 Web Applet。
  • 运行时动态生成,使用最多的就是动态代理技术。
  • 由其他文件生成,比如 JSP 应用场景,由 JSP 文件生成对应的 Class 文件。
  • 从数据库中读取,这种场景就比较小了。
  • 可以从加密文件中获取,这是典型的防止 Class 文件被反编译的保护措施。

加载阶段既可以使用虚拟机内置的引导类加载器来完成,也可以使用用户自定义的类加载器来完成。程序员可以通过自己定义类加载器来控制字节流的访问方式。


数组的加载不需要通过类加载器来创建,它是直接在内存中分配,但是数组的元素类型(数组去掉所有维度的类型)最终还是要靠类加载器来完成加载。

验证

加载过后的下一个阶段就是验证,因为我们上一步讲到在内存中生成了一个 Class 对象,这个对象是访问其代表数据结构的入口,所以这一步验证的工作就是确保 Class 文件的字节流中的内容符合《Java 虚拟机规范》中的要求,保证这些信息被当作代码运行后,它不会威胁到虚拟机的安全。


验证阶段主要分为四个阶段的检验:

  • 文件格式验证。
  • 元数据验证。
  • 字节码验证。
  • 符号引用验证。

文件格式验证
这一阶段可能会包含下面这些验证点:

  • 魔数是否以 0xCAFEBABE 开头。
  • 主、次版本号是否在当前 Java 虚拟机接受范围之内。
  • 常亮池的常量中是否有不支持的常量类型。
  • 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
  • CONSTANT_Utf8_info 型的常量中是否有不符合 UTF8 编码的数据。
  • Class 文件中各个部分及文件本身是否有被删除的或附加的其他信息。

实际上验证点远远不止有这些,上面这些只是从 HotSpot 源码中摘抄的一小段内容。


元数据验证
这一阶段主要是对字节码描述的信息进行语义分析,以确保描述的信息符合《Java 语言规范》,验证点包括

  • 验证的类是否有父类(除了 Object 类之外,所有的类都应该有父类)。
  • 要验证类的父类是否继承了不允许继承的类。
  • 如果这个类不是抽象类,那么这个类是否实现了父类或者接口中要求的所有方法。
  • 是否覆盖了 final 字段,是否出现了不符合规定的重载等。

需要记住这一阶段只是对《Java 语言规范》的验证。


字节码验证
字节码验证阶段是最复杂的一个阶段,这个阶段主要是确定程序语意是否合法、是否是符合逻辑的。这个阶段主要是对类的方法体(Class 文件中的 Code 属性)进行校验分析。这部分验证包括

  • 确保操作数栈的数据类型和实际执行时的数据类型是否一致。
  • 保证任何跳转指令不会跳出到方法体外的字节码指令上。
  • 保证方法体中的类型转换是有效的,例如可以把一个子类对象赋值给父类数据类型,但是不能把父
    类数据类型赋值给子类等诸如此不安全的类型转换。
  • 其他验证。

如果没有通过字节码验证,就说明验证出问题。但是不一定通过了字节码验证,就能保证程序是安全的。


符号引用验证
最后一个阶段的校验行为发生在虚拟机将符号引用转换为直接引用的时候,这个转化将在连接的第三个阶段,即解析阶段中发生。符号引用验证可以看作是对类自身以外的各类信息进行匹配性校验,这个验证主要包括

  • 符号引用中的字符串全限定名是否能找到对应的类。
  • 指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
  • 符号引用的类、字段方法的可访问性是否可被当前类所访问。
  • 其他验证。

这一阶段主要是确保解析行为能否正常执行,如果无法通过符号引用验证,就会出现类似
IllegalAccessError 、 NoSuchFieldError 、 NoSuchMethodError 等错误。
验证阶段对于虚拟机来说非常重要,如果能通过验证,就说明你的程序在运行时不会产生任何影响。

准备

准备阶段是为类中的变量分配内存并设置其初始值的阶段,这些变量所使用的内存都应当在方法区中进行分配,在 JDK 7 之前,HotSpot 使用永久代来实现方法区,是符合这种逻辑概念的。而在 JDK 8 之后,变量则会随着 Class 对象一起存放在 Java 堆中。


下面通常情况下的基本类型和引用类型的初始值除了"通常情况"下,还有一些"例外情况",如果类字段属性中存在 ConstantValue 属性,那就这个变量值在初始阶段就会初始化为 ConstantValue 属性所指定的初始值,比如

public static final int value = "666";

编译时就会把 value 的值设置为 666。

解析

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程。

  • 符号引用 :符号引用以一组符号来描述所引用的目标。符号引用可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,符号引用和虚拟机的布局无关。
  • 直接引用 :直接引用可以直接指向目标的指针、相对便宜量或者一个能间接定位到目标的句柄。直接引用和虚拟机的布局是相关的,不同的虚拟机对于相同的符号引用所翻译出来的直接引用一般是不同的。如果有了直接引用,那么直接引用的目标一定被加载到了内存中。

这样说你可能还有点不明白,我再换一种说法:

在编译的时候一个每个 Java 类都会被编译成一个 class 文件,但在编译的时候虚拟机并不知道所
引用类的地址,所以就用符号引用来代替,而在这个解析阶段就是为了把这个符号引用转化成为真
正的地址的阶段。

《Java 虚拟机规范》并未规定解析阶段发生的时间,只要求了在 anewarray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invokespecial、invokestatic、
invokevirtual、ldc、ldc_w、ldc2_w、multianewarray、new、putfield 和 putstatic 这 17 个用于操作符号引用的字节码指令之前,先对所使用的符号引用进行解析。
解析也分为四个步骤:

  • 类或接口的解析
  • 字段解析
  • 方法解析
  • 接口方法解析

初始化

初始化是类加载过程的最后一个步骤,在之前的阶段中,都是由 Java 虚拟机占主导作用,但是到了这一步,却把主动权移交给应用程序。


对于初始化阶段,《Java 虚拟机规范》严格规定了只有下面这六种情况下才会触发类的初始化。

  • 在遇到 new、getstatic、putstatic 或者 invokestatic 这四条字节码指令时,如果没有进行过初始化,那么首先触发初始化。通过这四个字节码的名称可以判断,这四条字节码其实就两个场景,调用 new 关键字的时候进行初始化、读取或者设置一个静态字段的时候、调用静态方法的时候。
  • 在初始化类的时候,如果父类还没有初始化,那么就需要先对父类进行初始化。
  • 在使用 java.lang.reflect 包的方法进行反射调用的时候。
  • 当虚拟机启动时,用户需要指定执行主类的时候,说白了就是虚拟机会先初始化 main 方法这个类。
  • 在使用 JDK 7 新加入的动态语言支持时,如果一个 jafva.lang.invoke.MethodHandle 实例最后的解析结果为 REF_getstatic、REF_putstatic、REF_invokeStatic、REF_newInvokeSpecial 四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,需要先对其进行初始化。
  • 当一个接口中定义了 JDK 8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果有这个借口的实现类发生了初始化,那该接口要在其之前被初始化。

其实上面只有前四个大家需要知道就好了,后面两个比较冷门。

如果说要答类加载的话,其实聊到这里已经可以了,但是为了完整性,我们索性把后面两个过程也
来聊一聊。

使用

这个阶段没什么可说的,就是初始化之后的代码由 JVM 来动态调用执行。

卸载

当代表一个类的 Class 对象不再被引用,那么 Class 对象的生命周期就结束了,对应的在方法区中的数据也会被卸载。

⚠️但是需要注意一点:JVM 自带的类加载器装载的类,是不会卸载的,由用户自定义的类加载器
加载的类是可以卸载的

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

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

相关文章

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑多能互补灵活性和用户低碳意愿的区域综合能源系统鲁棒优化调度》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

git - 笔记

为什么要学习Git 为什么要学习Git软件 为什么学习 因为在主流开发中,基于互联网软件开发的项目都会使用Git软件来进行项目开发过程中的资源管理 比如人力资源 代码资源 比如前端资源 .html .java等代码资源 文档资源 像项目开发中涉及到的需求文档等 这种项目中管理…

微服务超大Excel文件导出方案优化

1、在导出Excel时经常会碰到文件过大,导出特别慢 2、微服务限制了请求超时时间,文件过大情况必然超时 优化思路: 1、文件过大时通过文件拆分、打包压缩zip,然后上传到oss,并设置有效期(30天过期) 2、把…

kafka(三)springboot集成kafka(1)介绍

基于kafka新版本 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>3.0.0</version></dependency> </dependencies> 一、kafkaProducer 1、介绍…

Python工具小技巧

Python工具小技巧 将.py后缀文件转化为.exe后缀文件安装PyinstallerPyinstaller参数大全 将.py后缀文件转化为.exe后缀文件 目前比较常见的打包exe方法都是通过Pyinstaller来实现的&#xff0c;本文也将使用这种常规方法。 安装Pyinstaller 首先我们要先安装Pyinstaller&…

Sora的新商业视角:从生态构建到未来产业协同

在科技飞速发展的当下&#xff0c;人工智能与机器学习不仅重塑了我们的生活方式&#xff0c;还深刻地改变了商业模式的构建方式。Sora&#xff0c;作为一款前沿的AI视频生成工具&#xff0c;其盈利路径和未来产业协同的可能性值得深入探讨。 Sora学习资料&#xff1a;使用方式…

前端javascript的DOM对象操作技巧,全场景解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属的专栏&#xff1a;前端泛海 景天的主页&#xff1a;景天科技苑 文章目录 1.js的DOM介绍2.节点元素层级关系3.通过js修改&#xff0c;清空节点…

新零售SaaS架构:订单履约系统架构设计(万字图文总结)

什么是订单履约系统&#xff1f; 订单履约系统用来管理从接收客户订单到将商品送达客户手中的全过程。 它连接了上游交易&#xff08;客户在销售平台下单环&#xff09;和下游仓储配送&#xff08;如库存管理、物流配送&#xff09;&#xff0c;确保信息流顺畅、操作协同&…

基于单片机的商品RFID射频安全防盗报警系统设计

目 录 摘 要 I Abstract II 引 言 1 1 系统方案设计 3 1.1 总体设计要求 3 1.2 总体设计方案选择 3 1.3 总体控制方案选择 4 1.4 系统总体设计 5 2 项目硬件设计 7 2.1 单片机控制设计 7 2.2 按键电路设计 10 2.3 蜂鸣器报警电路设计 10 2.4 液晶显示电路设计 11 2.5 射频识别…

计算数据集的总体标准差pstdev()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算数据集的总体标准差 pstdev() [太阳]选择题 pstdev() 的作用是&#xff08;&#xff09; import statistics a [0, 0, 8, 8] print("【显示】a ",a) print("【执行】st…

C++ Qt开发:QHostInfo主机地址查询组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QHostInfo组件实现对主机地址查询功能…

考研复习-函数栈帧(详解)

目录 1. 什么是函数栈帧 2.函数栈帧的创建和销毁解析 2.1相关寄存器&#xff1a; 2.2相关汇编命令 运行代码&#xff1a; 3.预备知识&#xff1a; 4.正式开始&#xff1a; 4.1转到反汇编 4.2函数栈帧的创建 4.3函数栈帧的销毁 1. 什么是函数栈帧 我们在写C语言代码的时…

签约仪式如何策划和安排流程?如何邀约媒体现场见证报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 签约仪式的策划和安排流程&#xff0c;以及邀约媒体现场见证报道&#xff0c;都是确保活动成功和提升影响力的关键环节。以下是一些建议&#xff1a; 签约仪式的策划和安排流程 明确目标…

UE5 UE4 开发常用工具AssetDeveTool

AssetDeveTool工具&#xff0c;支持UE5 5.0-.5.3 UE4 4.26/4.27 下载链接&#xff1a; 面包多 https://mbd.pub/o/bread/ZZubkphu 工坊&#xff1a; https://gf.bilibili.com/item/detail/1104960041 包含功能&#xff1a; 自动化批量展UV功能 快速选择功能 自动化批量减面功能…

启动查看工具总结

启动目标&#xff1a;2s内优秀&#xff0c;2-5s普通&#xff0c;之后的都需要优化&#xff0c;热启动则是1.5s-2s内 1 看下大致串联启动流程&#xff1a; App 进程在 Fork 之后&#xff0c;需要首先执行 bindApplication Application 的环境创建好之后&#xff0c;就开始activ…

【CSP试题回顾】202109-2-非零段划分

CSP-202109-2-非零段划分 关键点&#xff1a;差分数组 详见&#xff1a;【CSP考点回顾】差分数组 时间复杂度分析 使用差分数组的优势在于&#xff0c;它将问题转化为了在一次遍历中识别并利用关键变化点&#xff08;波峰和波谷&#xff09;&#xff0c;从而避免了对每个可能…

【重要公告】BSV区块链协会开始对Teranode节点软件进行技术测试

​​发表时间&#xff1a;2024年2月22日 Teranode节点软件将使BSV区块链网络的交易处理速度提升至每秒110万笔&#xff0c;从而拓宽企业和政府客户的区块链应用范围。 2024年2月22日&#xff0c;瑞士楚格 - BSV区块链协会宣布已经开始对Teranode节点软件进行技术测试&#xff…

软考高级:系统工程生命周期阶段概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

Vue:自动按需导入element-plus图标

自动导入使用 unplugin-icons 和 unplugin-auto-import 从 iconify 中自动导入任何图标集。 完整vite.config.js参考模板 https://download.csdn.net/download/ruancexiaoming/88928539 导入element-plus图标 命令行安装unplugin-icons pnpm i -D unplugin-icons//没有安装自…

Vue中用户权限如何处理?

Vue中用户权限如何处理&#xff1f; 在 Vue 中&#xff0c;可以采用多种方式来处理用户权限&#xff0c;以下是一些常见的方法&#xff1a; 1. 使用路由守卫 Vue Router 提供了 beforeEach 导航守卫&#xff0c;可以在路由跳转之前进行权限检查。例如&#xff1a; router.be…