面试必问!JVM 不得不说的知识点(三)

news2024/11/25 1:06:48

在这里插入图片描述

一、 JVM指令集:

1. 了解Java虚拟机的指令集是什么?举例说明一些常见的指令及其作用。

Java虚拟机的指令集是一组用于执行Java程序的低级操作码。这些指令直接在Java虚拟机上执行,可以认为是Java程序的二进制表示形式。以下是一些常见的Java虚拟机指令及其作用的例子:

  1. iconst系列指令:

    • iconst_0, iconst_1, …, iconst_5: 将整数0到5推送到栈顶。
    • 作用:将常量整数压入栈顶。
  2. aloadastore系列指令:

    • aload_0, aload_1, …, aload_3: 将引用类型的局部变量加载到栈顶。
    • astore_0, astore_1, …, astore_3: 将栈顶引用类型的值存储到局部变量。
    • 作用:加载和存储引用类型数据。
  3. iloadistore系列指令:

    • iload_0, iload_1, …, iload_3: 将整数类型的局部变量加载到栈顶。
    • istore_0, istore_1, …, istore_3: 将栈顶整数类型的值存储到局部变量。
    • 作用:加载和存储整数类型数据。
  4. iaddisub等算术指令:

    • iadd: 将栈顶两个整数相加。
    • isub: 将栈顶两个整数相减。
    • 作用:执行整数加法和减法。
  5. gotoif系列指令:

    • goto: 无条件跳转到指定位置。
    • ifeq, ifne, iflt, ifge, ifgt, ifle: 根据栈顶整数的值进行条件跳转。
    • 作用:实现无条件和有条件的跳转。
  6. invoke系列指令:

    • invokevirtual, invokestatic, invokespecial, invokeinterface, invokedynamic: 分别用于调用实例方法、静态方法、私有方法、接口方法和动态方法。
    • 作用:执行方法调用。
  7. newnewarray指令:

    • new: 创建一个新的对象。
    • newarray: 创建一个新的基本数据类型数组。
    • 作用:创建对象和数组。
  8. putfieldgetfield指令:

    • putfield: 将栈顶的值赋给对象的实例字段。
    • getfield: 将对象的实例字段的值推送到栈顶。
    • 作用:访问对象的实例字段。

这些指令是Java虚拟机指令集中的一部分,涵盖了基本的栈操作、变量加载存储、数学运算、控制流等功能。在Java字节码中,这些指令按照字节码的格式被编码,并在Java虚拟机中执行。

二、 对象模型和内存布局:

1.描述Java对象在内存中的布局,包括对象头、实例数据和对齐等方面。

Java对象在内存中的布局主要包括对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)等三个部分。具体的布局可以因为虚拟机的不同而有所差异,以下是通用情况下的描述:

  1. 对象头(Header):

    • 对象头用于存储对象自身的运行时数据,包括哈希码、锁状态标志、垃圾回收信息等。对象头的大小在不同的虚拟机实现中可能会有所不同,通常在32位系统上占用8字节,而在64位系统上占用12字节。
    • 其中,包含:
      • Mark Word(标记字): 存储对象的哈希码、锁信息等。
      • Klass Pointer(类型指针): 指向对象的类元数据。
  2. 实例数据(Instance Data):

    • 实例数据部分包含了对象的字段,即在类中声明的各种成员变量。字段的大小和对齐方式由字段的类型和虚拟机的要求决定。
    • 实例数据的布局是按照在类中声明的顺序排列的,不同的虚拟机可能对字段的排列进行一些优化。
  3. 对齐填充(Padding):

    • 由于虚拟机要求对象的起始地址必须是8字节的整数倍(在某些平台上可能是4字节的整数倍),因此可能需要对实例数据进行对齐填充,以保证整个对象的大小是8字节的倍数(或4字节的倍数)。
    • 对齐填充的大小取决于实例数据部分的大小,以确保整个对象的总大小满足对齐要求。

下面是一个简单的示意图,表示一个Java对象在内存中的布局:

------------------
|  对象头(Header) |
------------------
| 实例数据(Instance Data)|
------------------
|  对齐填充(Padding)  |
------------------

在不同的虚拟机和不同的场景下,对象的布局可能会有一些变化,但以上描述是一般情况下的Java对象在内存中的典型布局。要注意,具体的实现可能因为虚拟机的版本、配置和运行时环境的不同而有所调整。

2. 什么是对象的标记字(Mark Word)?

对象的标记字(Mark Word)是Java对象头中的一部分,用于存储对象的运行时信息。在Java虚拟机的内存模型中,每个对象都有一个对象头,其中的标记字包含了对象的一些元信息,如锁信息、垃圾回收状态等。

标记字的具体结构和含义可能会因虚拟机的实现而有所不同,但通常包含以下信息:

  1. 哈希码(HashCode):

    • 用于支持hashCode()方法。在对象被创建时,如果没有重写hashCode()方法,标记字中的哈希码将默认由对象的地址计算得到。
  2. 锁信息(Lock Information):

    • 用于支持对象的同步机制。在多线程环境中,Java对象可能会被多个线程同时访问,因此需要进行加锁以确保数据的一致性。标记字中的锁信息包括了对象的锁状态、锁持有的线程等信息。
  3. 垃圾回收信息:

    • 用于支持垃圾回收。标记字中的垃圾回收信息包括了对象的存活状态、分代信息等。这些信息有助于垃圾回收器判断对象是否可被回收。
  4. 偏向锁标志(Biased Lock Flag):

    • 用于标识对象是否处于偏向锁状态。在Java虚拟机中,偏向锁是一种提高同步性能的机制。当对象被某个线程锁定时,可以使用偏向锁来减少获取锁的开销。

标记字的具体位数和结构可能因虚拟机的不同而异。在64位虚拟机中,通常使用64位来存储标记字。在32位虚拟机中,标记字的大小可能是32位。

对象的标记字是Java虚拟机管理对象的关键信息之一,它在支持同步、垃圾回收等方面发挥着重要的作用。标记字的设计可以根据不同的虚拟机实现和需求有所差异。

三、 栈和本地方法栈:

1. 解释栈的结构,栈帧的组成,以及方法调用时栈的变化。

栈(Stack)是Java虚拟机用来执行方法调用的数据结构,每个线程都有自己的栈。栈是一个后进先出(LIFO)的数据结构,用于存储方法的局部变量、操作数栈、动态链接、方法出口等信息。在Java虚拟机中,栈的结构主要由栈帧构成。

栈帧(Stack Frame)的组成:

栈帧是用于支持方法调用和执行的数据结构,每个方法调用都会创建一个对应的栈帧。栈帧的组成通常包括以下几个部分:

  1. 局部变量表(Local Variable Table):

    • 用于存储方法中的局部变量,包括方法参数和在方法体内部定义的局部变量。局部变量表中的槽位可以存放基本数据类型和对象引用。
  2. 操作数栈(Operand Stack):

    • 用于存储方法执行过程中的操作数。在方法调用时,参数从局部变量表传递到操作数栈,方法执行时,操作数栈用于存储临时数据和中间结果。
  3. 动态链接(Dynamic Linking):

    • 指向运行时常量池的方法引用,包括类和方法的信息。动态链接支持方法调用时的动态绑定。
  4. 方法返回地址(Return Address):

    • 指向方法调用结束后需要返回的地址。在Java虚拟机中,方法的返回地址通常是指向方法调用指令的下一条指令。
  5. 帧数据(Frame Data):

    • 用于存储一些附加的信息,例如异常处理表(Exception Table)等。

方法调用时栈的变化:

  1. 方法调用过程:

    • 当一个方法被调用时,Java虚拟机会创建一个新的栈帧并推入栈顶,该栈帧包含了方法的局部变量表、操作数栈等信息。
    • 方法参数被传递到局部变量表中,方法的操作数栈被清空。
  2. 方法执行过程:

    • 在方法执行过程中,局部变量表和操作数栈用于存储和计算方法中的数据。
    • 操作数栈用于存放中间结果、方法调用的参数和返回值。
  3. 方法返回过程:

    • 当方法执行完成时,返回地址和方法的返回值等信息从栈帧中弹出,控制权返回给调用方法。
    • 调用方法的栈帧被弹出,控制权回到调用方法的栈帧。
  4. 递归调用:

    • 在递归调用中,每次方法调用都会创建一个新的栈帧,形成一个栈帧的链条。这些栈帧在栈中依次排列,每个栈帧负责一个方法的执行。

栈的结构和栈帧的组成是支持Java方法调用和执行的关键。在方法调用过程中,栈帧的入栈和出栈使得方法的执行能够进行,同时局部变量表和操作数栈的使用保证了方法执行时的数据存储和计算。

2. 本地方法栈和虚拟机栈有何异同?

本地方法栈(Native Method Stack)和虚拟机栈(Java Virtual Machine Stack)都是Java虚拟机在运行时使用的栈结构,但它们分别用于支持不同类型的方法调用。

本地方法栈(Native Method Stack):

  1. 作用:

    • 本地方法栈用于支持Java虚拟机使用本地方法(Native Method),即用其他语言(通常是C或C++)编写的方法。
  2. 存储内容:

    • 存储的是本地方法的调用和执行信息。本地方法是通过Java Native Interface(JNI)调用的,其实现是由其他语言编写的。
  3. 内存管理:

    • 本地方法栈与虚拟机栈的管理方式相似,都是通过栈帧来管理方法调用的信息。但本地方法栈的管理通常由本地方法库负责,而不是由Java虚拟机直接管理。
  4. 可能性:

    • 并非所有的Java虚拟机实现都提供本地方法栈,某些虚拟机将本地方法栈和虚拟机栈合二为一。

虚拟机栈(Java Virtual Machine Stack):

  1. 作用:

    • 虚拟机栈用于支持Java方法的调用和执行。
  2. 存储内容:

    • 存储的是Java方法的调用和执行信息,包括局部变量表、操作数栈、动态链接等。
  3. 内存管理:

    • 虚拟机栈由Java虚拟机直接进行管理,它的栈帧中包含了方法的执行信息,并且可以在方法调用时动态地分配和释放栈帧。
  4. 异常处理:

    • 虚拟机栈中还包含了用于异常处理的信息,当方法出现异常时,虚拟机会在虚拟机栈中找到对应的异常处理器进行处理。

异同点总结:

  1. 调用对象:

    • 本地方法栈用于调用本地方法,而虚拟机栈用于调用Java方法。
  2. 存储内容:

    • 本地方法栈存储本地方法的调用和执行信息,虚拟机栈存储Java方法的调用和执行信息。
  3. 内存管理:

    • 本地方法栈的内存管理通常由本地方法库负责,虚拟机栈由Java虚拟机直接进行管理。
  4. 异常处理:

    • 虚拟机栈中包含了用于异常处理的信息,而本地方法栈可能不包含这样的信息。

本地方法栈和虚拟机栈都是为了支持方法调用和执行而设计的,但它们服务于不同类型的方法,具有不同的内存管理机制。

四、 深入分析类加载机制:

1.类加载过程中,具体每个阶段发生了什么?

类加载是Java虚拟机将类的二进制数据加载到内存中,并转换为可以被虚拟机直接使用的数据结构的过程。类加载过程主要包括以下阶段:

  1. 加载(Loading)阶段:

    • 加载阶段是类加载的第一阶段。在加载阶段,虚拟机需要完成以下任务:
      • 通过类的全限定名获取类的二进制数据流。
      • 将二进制数据流转换成方法区的数据结构。
      • 在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
  2. 连接(Linking)阶段:

    • 连接阶段包括三个子阶段:验证、准备和解析。
      • 验证(Verification): 确保加载的类是符合Java虚拟机规范的,不会对虚拟机造成危害。
      • 准备(Preparation): 为类的静态变量分配内存并设置默认初始值,这些变量所使用的内存都在方法区中分配。
      • 解析(Resolution): 将符号引用解析为直接引用。符号引用是一组符号来描述被引用的目标,直接引用可以是直接指向目标的指针、相对偏移量或一个能间接定位到目标的句柄。
  3. 初始化(Initialization)阶段:

    • 在初始化阶段,虚拟机执行类的初始化语句。这是类加载过程的最后一步,它包括:
      • 执行类的初始化方法(<clinit>),该方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块(static {})中的语句合并产生的。
      • 如果一个类在初始化时发现它的父类还没有被初始化,则需要先触发其父类的初始化。

需要注意的是,不是所有类的加载阶段都经历完整的连接和初始化。比如,接口中定义的变量默认是public static final的,它们在接口的连接阶段就会被初始化为常量值,并不需要等到初始化阶段。而类变量则会在初始化阶段才被赋值。

2、如果要实现一个自定义类加载器,你会怎么做?

实现自定义类加载器通常需要继承ClassLoader类,并重写其中的findClass方法。以下是实现自定义类加载器的一般步骤:

  1. 继承ClassLoader类:

    • 创建一个新的类,继承自ClassLoader
    public class CustomClassLoader extends ClassLoader {
         
        // 实现自定义类加载器的方法
    }
    
  2. 重写findClass方法:

    • 在自定义类加载器中,需要重写findClass方法。这个方法负责加载类的二进制字节码并转换为Class对象。
    @Override
    protected Class<?> findClass(String className) throws ClassNotFoundException {
         
        // 实现加载类的逻辑,将二进制数据转换为Class对象
        byte[] classData = loadClassData(className);
        if (classData == null<

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

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

相关文章

微信小程序 ---- 生命周期

目录 生命周期 1. 小程序运行机制 2. 小程序更新机制 3. 生命周期介绍 4. 应用级别生命周期 5. 页面级别生命周期 6. 生命周期两个细节补充说明 7. 组件生命周期 总结 生命周期 1. 小程序运行机制 冷启动与热启动&#xff1a; 小程序启动可以分为两种情况&#xff0…

【云动世纪:Apache Doris 技术之光】

本文节选自《基础软件之路&#xff1a;企业级实践及开源之路》一书&#xff0c;该书集结了中国几乎所有主流基础软件企业的实践案例&#xff0c;由 28 位知名专家共同编写&#xff0c;系统剖析了基础软件发展趋势、四大基础软件&#xff08;数据库、操作系统、编程语言与中间件…

基于Android的校园请假App的研究与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【进程创建】

目录 进程创建的方式查看进程pid 调用系统调用创建子进程fock函数做了的工作子进程刚开始创建的状态 一个变量&#xff0c;两个不同的值创建子进程的作用 进程创建的方式 1.在操作系统上输入的指令。 2.已经启动的软件。 3.程序员在代码层面上调用系统调用创建进程。 linux中第…

什么是MES?SCADA与MES有什么区别?

连接制造过程的各个层是构建更有效的操作和自动化系统的关键步骤。SCADA(监控和数据采集)、MES(制造执行系统)和 ERP(企业资源规划)是制造过程中最重要的三个级别。 SCADA用于工厂车间的自动化&#xff0c;ERP在办公室层面自动执行许多任务。MES系统占据了SCADA和ERP之间的空间…

一款跳转警告HTML单页模板源码

一款跳转警告HTML单页模板,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 代码如下 <!DOCTYPE html> <html> <!--QQ沐编程 www.q…

【刷题记录】相交链表

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 1.题目链接&#xff1a; LINK 2.详解思路&#xff1a; 思路1&#xff1a;用尾结点是否一样来判断是否相交&#xff0c;用相对移位来找到结点 思路2&#xff1a;双层嵌套循环&#xff0c;时间复杂度O&#xff08;N*N&…

06 flink 的各个角色的交互

前言 这里主要是 涉及到 flink 中各个角色的交互 TaskManager 和 ResourceManager 的交互 JobMaster 和 ResourceManager 的交互 等等流程 TaskManager 和 ResourceManager 的交互 主要是 包含了几个部分, 如下, 几个菜单 TaskManager向 ResourceManager 注册 Resou…

学习Markdown

https://shadows.brumm.af 欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些…

第101讲:Mycat分布式数据库代理系统的核心概念以及部署

文章目录 1.Mycat核心概念1.1.Mycat介绍1.2.Mycat的应用场景1.3.Mycat结构概念1.4.Mycat的原理1.5.Mycat管理 2.部署Mycat 1.Mycat核心概念 1.1.Mycat介绍 Mycat是开源的、活跃的、基于JAVA语言编写的MySQL数据库中间件&#xff0c;可以把它看做是一个代理程序&#xff0c;开…

MariaDB落幕和思考

听过MySQL的基本也都知道 MariaDB。MariaDB由MySQL的创始人主导开发&#xff0c;他早前曾以10亿美元的价格&#xff0c;将自己创建的公司MySQL AB卖给了SUN&#xff0c;此后&#xff0c;随着SUN被甲骨文收购&#xff0c;MySQL的所有权也落入Oracle的手中。传闻MySQL的创始人担心…

融中穿刺路径角度评估的C++技术实现

消融模型的三维渲染 我们以肝部为例&#xff0c;通常肝部在做消融手术规划时有几个步骤。 一三维重建&#xff1a; 对器官进行图像分割&#xff1b; 对肿瘤的原发区域GTV进行勾画。 二穿刺路径的规划&#xff1a; 路径规划当中有几个约束&#xff1a;穿刺深度、危及器官的…

普中51单片机(DS18B20温度传感器)

DS18B20温度传感器原理 内部结构 64位(激)光刻只读存储器 光刻ROM中的64位序列号是出厂前被光刻好的&#xff0c;它可以看作是该DS18B20的地址序列号。64位光刻ROM的排列是&#xff1a;开始8位&#xff08;28H&#xff09;是产品类型标号&#xff0c;接着的48位是该DS18B20自身…

论文精读--GPT1

把transformer的解码器拿出来&#xff0c;在没有标号的大量文本数据上训练一个语言模型&#xff0c;来获得预训练模型&#xff0c;然后到子任务上微调&#xff0c;得到每个任务所需的分类器 Abstract Natural language understanding comprises a wide range of diverse tasks…

祝贺!湖南天府生态农业有限公司喜获“湖南省生猪核心育种场”授牌

为贯彻落实全国畜禽遗传改良计划&#xff0c;根据《湖南省种业振兴行动实施方案》以及省农业农村厅办公室《关于开展省级种畜禽核心场遴选工作的通知》&#xff0c;湖南省农业农村厅组织省畜禽遗传资源委员会在全省范围内开展了省级畜禽核心育种场遴选工作。 经养殖场申请、市县…

解决SSH远程登录开饭板出现密码错误问题

输入“adduser Zhanggong回车”&#xff0c;使用adduser命令创建开发板用户名为Zhanggong 输入密码“123456” 输入密码“123456”

华清远见作业第四十一天——Qt(第三天)

思维导图&#xff1a; 编程 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如…

OpenAI Sora视频模型技术原理报告解读

▌01. OpenAI Sora 视频生成模型技术报告总结 •不管是在视频的保真度、长度、稳定性、一致性、分辨率、文字理解等方面。 •技术细节写得比较泛&#xff08;防止别人模仿&#xff09;大概就是用视觉块编码&#xff08;visual patch&#xff09;的方式&#xff0c;把不同格…

k8s-heml联动harbor 18

将打包的heml包上传到harbor仓库进行管理 创建一个公开的项目来接收传送的heml包 安装helm-push插件&#xff1a; helm plugin install https://github.com/chartmuseum/helm-push &#xff08;在线安装&#xff0c;要求网速要快或者提供科学上网&#xff09; 离线安装&…

庖丁解牛-二叉树的遍历

庖丁解牛-二叉树的遍历 〇、前言 01 文章内容 一般提到二叉树的遍历&#xff0c;我们是在说 前序遍历、中序遍历、后序遍历和层序遍历 或者说三序遍历层序遍历&#xff0c;毕竟三序和层序的遍历逻辑相差比较大下面讨论三序遍历的递归方法、非递归方法和非递归迭代的统一方法然…