java(JVM)

JVM

Java的JVM(Java虚拟机)是运行Java程序的关键部件。它不直接理解或执行Java源代码,而是与Java编译器生成的字节码(Bytecode)进行交互。下面是对Java JVM更详尽的解释:

1.字节码

当你使用Java编译器(javac)编译Java源代码时,会生成一种中间语言——字节码(.class文件)。字节码是一种平台无关的代码格式,设计目的是为了实现跨平台的兼容性。

字节码(Bytecode)是一种介于高级编程语言和机器语言之间的低级程序表示形式。它是许多编程语言(如Java、Python等)在编译或解释执行过程中产生的中间代码。字节码的主要特点和作用包括:

  1. 平台无关性:字节码不针对任何特定的硬件架构,它是一种抽象的、与具体处理器无关的指令集。这使得编译后的字节码可以在任何支持该字节码格式的平台上运行,实现了“一次编写,到处运行”的跨平台特性。

  2. 简化编译过程:相比直接生成机器语言,产生字节码的过程更为简单,因为字节码的指令集通常比机器语言指令集更小、更通用。

  3. 安全性增强:在执行字节码前,虚拟机(如Java虚拟机JVM)可以对其进行验证,确保代码的安全性,比如检查类型安全,防止非法访问内存等。

  4. 优化机会:JVM或其他虚拟机可以在运行时对字节码进行动态优化,如即时编译(JIT),将频繁执行的字节码转换为更高效的本地机器码,提高程序执行效率。

  5. 易于分析与变换:由于字节码的结构较为简单且有明确的规范,工具和框架可以更容易地对其进行分析、修改或转换,这对于代码混淆、程序分析、动态代理等技术尤为重要。

例如,在Java中,源代码被编译成.class文件中的字节码,这些字节码随后由Java虚拟机(JVM)解释或即时编译成机器码执行。这一层抽象极大地增强了Java程序的可移植性和安全性。

2.加载与验证

当一个Java程序开始运行时,JVM负责加载所需的字节码文件。加载后,JVM会对这些字节码进行验证,确保它们没有违反Java的安全规范,如类型安全等。

Java 虚拟机(JVM)的类加载过程主要包括五个阶段:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)和初始化(Initialization)。下面是对加载与验证阶段的详细介绍:

加载(Loading)

  1. 寻找并加载类的二进制数据:JVM查找并读取类的字节码文件(通常是.class文件),这个过程可以通过不同的类加载器来完成,包括启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、系统类加载器(Application ClassLoader)或自定义类加载器。

  2. 创建java.lang.Class实例:JVM为每个加载的类创建一个对应的Class对象,作为方法区中类数据的访问入口。这个对象封装了类的各种信息,如类名、父类、实现的接口、常量池、字段、方法等。

验证(Verification)

验证阶段是确保加载的字节码是否符合JVM规范要求,防止恶意代码损害系统安全。验证过程分为四个主要步骤:

3.文件格式验证

检查.class文件的格式是否正确,包括魔数(Magic Number)、版本号、常量池等,确保文件结构合法。

Java虚拟机(JVM)的文件格式验证是类加载验证过程的第一个阶段,旨在确保.class文件的格式遵守Java Class File Format规范,确保字节码文件的基本结构正确无误,可以被正确解析。此阶段的验证内容主要包括以下几个方面:

  1. 魔数验证(Magic Number Verification):每个.class文件的开头都有一个特殊的4字节序列(十六进制表示为CAFEBABE),被称为魔数。验证器首先检查文件头的魔数是否正确,以此确认文件是否为有效的Java字节码文件。

  2. 版本信息验证:接下来验证.class文件的版本号,包括主版本号和次版本号,确保其与当前JVM的版本兼容。如果不兼容,JVM将拒绝加载该类。

  3. 常量池计数和验证:验证常量池的数量是否与文件中声明的一致,并对常量池中的每一项(如类名、字符串、数字、方法引用等)进行基本的格式验证,确保它们的类型和结构正确。

  4. 访问标志验证:检查类或接口的访问修饰符是否合法,例如确保一个类不能同时被声明为abstractfinal

  5. 类索引、父类索引和接口计数验证:确保类索引指向的常量池项确实代表一个有效的类,父类索引(对于非java.lang.Object的类)指向的是一个有效的超类,接口计数正确无误,且所有接口引用有效。

  6. 字段表和方法表验证:验证类的字段和方法数量是否与声明相符,以及字段和方法的描述符是否合法,包括返回类型、参数类型等。

  7. 属性表验证:检查类、字段和方法的属性表,确保属性的数量、类型和长度正确,特别是对Code属性(包含方法的字节码)的初步检查,以确保其格式合理。

文件格式验证主要是对.class文件的结构进行检查,确保其基本的格式和一致性,是整个类加载验证流程的基础。如果这一阶段检测到任何错误,类加载过程就会终止,并抛出相关错误信息。

4.元数据验证

校验类的元数据信息,如检查类是否有父类(除了java.lang.Object外)、检查final类是否被继承、检查方法的重写是否遵循规则等。

Java虚拟机(JVM)的元数据验证是类加载验证过程的第二个阶段,紧随文件格式验证之后。这一阶段主要关注类结构的语义检查,确保类的元数据信息(如类、接口、字段、方法等)遵循Java语言规范,不会引入逻辑上的冲突或不一致性。元数据验证的具体内容包括但不限于以下几个方面:

  1. 类结构验证:确保类的继承关系合法,例如一个类只能有一个直接父类(除了java.lang.Object外),接口不能有父类,类不能直接或间接实现自己,也不能直接或间接扩展自己。

  2. 字段和方法重载验证:检查类中的字段和方法名称是否唯一(考虑重载的情况下),以及它们的访问权限、修饰符(如staticfinalprivate等)是否合法。

  3. final类和方法验证:确保声明为final的类没有子类,final的方法没有被子类重写。

  4. 抽象类和方法验证:如果一个类声明为抽象类,验证它是否有子类;如果一个方法声明为抽象方法,确保它在非抽象类中不被实现。

  5. 接口验证:确保接口不包含实例字段(除了static final),所有方法都是抽象的(Java 8之后允许默认方法和静态方法),接口不能继承自非接口类型。

  6. 常量池中的符号引用验证:虽然符号引用的完全解析发生在解析阶段,但在元数据验证期间也会对常量池中的某些符号引用进行基本的格式检查,确保它们指向的描述符(如类、方法、字段的描述符)语法上是正确的。

元数据验证是确保类定义逻辑正确性的关键步骤,它帮助JVM识别那些在文件格式上看似正确但实际上违反了Java语言规范的类。通过这一系列严格的检查,JVM能够排除那些在类结构上有潜在问题的类,从而提升系统的稳定性和安全性。

5.字节码验证

这是最复杂的一个阶段,通过数据流分析和控制流分析等手段,确保字节码的语义是合法的,不会引起 JVM 执行时的异常,比如类型转换错误、跳转指令的合法性等。

Java虚拟机(JVM)的字节码验证是类加载验证过程中的第三个阶段,也是最为复杂和关键的一个环节。这一阶段的目标是确保字节码的语义正确性,防止非法或有害的操作,保证程序执行的安全性。字节码验证主要关注以下几个方面:

  1. 类型安全验证:这是字节码验证的核心部分,涉及数据流分析和控制流分析。它检查每个操作码(opcode)对操作数栈和局部变量表的操作是否类型安全,确保不会发生类型不匹配的错误,比如错误的类型转换、非法的运算操作等。例如,确保加法操作的两个操作数都是数值类型,且类型兼容。

  2. 控制流验证:分析字节码的控制流图,确保程序的控制流逻辑是合理的,没有死循环,也不会跳转到不存在的指令或非法的代码段。此外,还检查异常处理表的正确性,确保try-catch块的范围合理且捕获的异常类型与抛出的异常匹配。

  3. 操作数栈和局部变量表的平衡性验证:确保每个方法的执行过程中,操作数栈和局部变量表的使用前后保持平衡,即每条指令执行前后栈深度和局部变量的使用状态符合预期,不会出现栈溢出或下溢的情况。

  4. 方法体验证:详细检查方法内部的代码,包括对方法的Code属性中的字节码指令序列进行验证,确保指令的顺序、分支、跳转逻辑正确,以及对方法返回类型和异常处理的合规性检查。

  5. 对常量池引用的额外验证:在这一阶段,虽然大部分符号引用的解析发生在解析阶段,但对于直接涉及到的常量池条目(如方法调用、字段访问等),会进一步验证这些引用的有效性和类型兼容性。

字节码验证是JVM安全机制的重要组成部分,通过严格的逻辑检查,可以有效防止恶意代码利用字节码层面的漏洞进行攻击,保证了Java程序的健壮性和安全性。尽管这一过程相对耗时,但它对维护Java“一次编写,到处运行”的承诺至关重要。

6.符号引用验证

在解析之前对类自身以外的信息(如常量池中的类、方法、字段符号引用)进行校验,确保可以成功解析到对应的类、方法或字段。

符号引用验证是Java虚拟机(JVM)类加载验证过程中的第四个阶段,发生在解析之前。这一阶段主要关注常量池中的符号引用(Symbolic References),确保这些引用在实际解析时能够成功定位到目标类、字段或方法。符号引用验证包括以下几个方面:

  1. 有效性验证:检查常量池中的符号引用是否格式正确,比如类或接口的全限定名、字段的名称和描述符、方法的名称、描述符及参数类型等,确保这些信息符合Java语言规范。

  2. 可访问性验证:确保当前类对符号引用所指的目标具有合法的访问权限。例如,私有(private)成员不能被外部类访问,包外的类不能访问包内未声明为public的成员等。

  3. 存在性验证:验证被引用的类、字段、方法是否真实存在。虽然这一步骤在实际解析时会更加彻底,但在符号引用验证阶段也会进行初步检查,避免明显的无效引用。

  4. 类型兼容性验证:对于方法调用和字段访问,检查调用者和被调用者之间是否存在兼容性问题,比如方法的参数类型、返回类型与预期是否一致,字段类型是否兼容等。

  5. 接口合法性验证:如果符号引用指向的是接口方法或接口本身,确保符合Java接口的使用规则,比如类实现接口的所有抽象方法,或者接口不能继承自非接口等。

符号引用验证的目的在于提前发现潜在的引用错误,减少在解析阶段因引用问题导致的失败,从而提高类加载的效率和稳定性。虽然解析阶段会进一步验证和具体化这些符号引用,但前期的符号引用验证依然是必要的,它作为一道安全网,有助于维护Java程序的健壮性。

验证阶段是非常重要的,它确保了类文件的格式正确、语义合法,是JVM安全机制的重要组成部分。如果在验证阶段发现错误,JVM将抛出相关异常,阻止有问题的类被加载到内存中执行。

  1. 解释与即时编译(JIT):早期的JVM通过逐行解释字节码来执行程序,这种方式效率较低。现代JVM大多采用即时编译技术(Just-In-Time Compilation),即在运行时将频繁执行的字节码编译为对应平台的本地机器码,从而显著提升执行效率。

  2. 内存管理:JVM自动管理程序运行时的内存分配和回收。它将内存划分为不同的区域,如堆(Heap)用于存储对象实例,栈(Stack)用于方法调用和局部变量,以及方法区(Method Area)用于存储类的元数据等。垃圾收集器(Garbage Collector, GC)是JVM的一部分,负责自动回收不再使用的内存空间,减少程序员手动管理内存的工作。

  3. 多线程支持:JVM内置了对多线程的支持,使得Java程序可以轻松创建和管理多个线程。JVM负责调度线程、管理线程生命周期,并提供了一套内存模型来保证线程间的通信正确性。

  4. 安全性:JVM通过字节码验证、安全沙箱(限制了程序访问本地系统资源的能力)、类加载器体系结构等多种机制来保障Java程序的执行安全。

正因为有了JVM,Java程序员编写的代码可以在任何安装了JVM的硬件和操作系统上运行,无需重新编译,实现了高度的可移植性和跨平台能力。

GC算法(垃圾回收算法)

Java虚拟机中的垃圾回收算法主要有以下几种:

  1. 标记-清除(Mark and Sweep)

    • 这是最基础的垃圾回收算法。首先遍历所有可达的对象并做上标记,然后再次遍历堆内存,未被标记的对象被视为垃圾并回收其空间。
    • 缺点是会产生内存碎片,导致后续分配大对象时可能无法找到足够的连续空间。
  2. 复制(Copying)

    • 将内存分为两个相等的区域,每次只使用其中一个区域。当这一区域满时,将存活对象复制到另一个区域,然后清空之前使用的区域。
    • 这种方法简单高效,能解决内存碎片问题,但代价是内存使用率只有50%。
  3. 标记-整理(Mark and Compact)

    • 结合了标记-清除和复制的优点,首先标记出所有活动对象,然后将存活的对象向一端移动,最后清理掉边界外的内存空间。
    • 这个过程既解决了碎片问题,又不需要两倍的内存空间。
  4. 分代收集(Generational Collection)

    • 基于“大多数对象都是朝生夕灭”的假设,将堆内存分为新生代和老年代。
    • 新生代通常使用复制算法,因为它频繁GC但每次回收的大多是短命对象。
    • 老年代则常用标记-清除或标记-整理算法,因为这里的对象生命周期长,回收频率低。

垃圾回收器

JVM提供了多种垃圾回收器,它们实现了上述算法的不同组合,以适应不同场景的需求。以下是一些常见的垃圾回收器:

  1. Serial GC:适用于单CPU环境,新生代和老年代都采用串行回收的方式,简单高效但无法充分利用多核处理器的优势。

  2. Parallel GC(也称为Throughput Collector):在多CPU环境中并行进行垃圾回收,提高吞吐量,但可能会引起较长的暂停时间。

  3. Concurrent Mark and Sweep (CMS) GC:老年代垃圾回收器,目标是减少停顿时间,大部分工作与用户线程并发执行,但在极端情况下可能会出现“ Concurrent Mode Failure”。

  4. G1(Garbage First)GC:设计用于大型堆的服务器应用,它将堆内存划分为多个大小相等的区域(Region),并采用分代收集策略,同时努力达到低延迟和高吞吐量的目标。

类加载机制

Java的类加载机制主要包括以下步骤:

  1. 加载(Loading):查找并加载类的二进制数据,通常是.class文件。

  2. 验证(Verification):检查加载的类是否有正确的内部结构,并符合Java语言规范。

  3. 准备(Preparation):为类的静态变量分配内存,并将其初始化为默认值。

  4. 解析(Resolution):将常量池中的符号引用转换为直接引用的过程,如果需要的话。

  5. 初始化(Initialization):执行类的静态初始化代码,给静态变量赋予程序员设定的初始值。

类加载器分为四种主要类型:Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader 和 Custom ClassLoader(用户自定义)。它们形成了一个层次结构,负责加载不同来源的类,且遵循双亲委派模型原则,即类加载请求先委托给父加载器处理,如果父加载器不能处理再由自己尝试加载。

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

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

相关文章

【elementui源码解析】如何实现自动渲染md文档-第一篇

文章目录 目录 背景 获取源码 代码分析 背景 之前基于vant3的源码开发过二次开发过组件,其中vant实现了将md文档渲染到界面上,有天突发奇想想知道这是如何实现的将md文档渲染到界面上的,因为平时开发中使用elementui占多数,所…

【kaggle量化交易第一名方案】Trading at the Close

2024 1st Place Solution Overview 最终模型(CV/Private LB为5.8117/5.4030)是CatBoost(5.8240/5.4165)、GRU(5.8481/5.4259)和Transformer(5.8619/5.4296)的组合,权重分别为0.5、0.3、0.2,从验证集中搜索得到。这些模型共享相同的300个特征。 此外,在线学习(On…

docker的教程长亭

把我的常用docker写在这里 之前用 vul - hub 靶场经常用 现在docker不知道为什么挂了 开启 docker-compose up -d 关闭 docker-compose down docker ps 只是运行 docker ps -a 所有 包括停止 docker ps -q 只看id docker stop <container_name_or_id> docker 的容器…

Linux Debian12使用podman安装xss-labs靶场环境

一、xss-labs简介 xss-labs靶场是一个专门用于学习和练习跨站脚本攻击&#xff08;XSS&#xff09;技术的在线平台。它提供了一系列的实验场景和演示&#xff0c;帮助安全研究人员、开发人员和安全爱好者深入了解XSS攻击的原理和防御方法。 二、安装podman环境 Linux Debian…

SylixOS下UDP组播测试程序

SylixOS下UDP组播测试 测试效果截图如下: udp组播发送测试程序。 /********************************************************************************************************* ** ** 中国软件开源组织 ** ** …

vite配置unocss

在vue3vitetseslintprettierstylelinthuskylint-stagedcommitlintcommitizencz-git介绍了关于vitevue工程化搭建&#xff0c;现在在这个基础上&#xff0c;我们增加一下unocss unocss官方文档 具体开发中使用遇到的问题可以参考不喜欢原子化CSS得我&#xff0c;还是在新项目中使…

H5单点登录分析介绍(登录状态检验状态透传分析)

文章目录 1、单点登录解决方案1.1、后端保存登录状态1.2、token模式 2、user服务-登录接口2.1、UserController2.2、UserInfoServiceImpl2.3、载荷2.4、响应2.5、Redis Desktop Manager 3、user服务-登录成功获取用户信息回显3.1、UserController3.2、UserInfoServiceImpl3.3、…

【kubernetes】k8s中包管理工具-----Helm 超详细解读

目录 一、Helm 1.1什么是 Helm 1.2Helm 有三个重要的概念 1.2.1Chart 1.2.2Repository&#xff08;仓库&#xff09; 1.2.3Release 1.3Helm3 与 Helm2 的区别 二、Helm 部署 2.1安装 helm 2.2命令补全 2.3使用 helm 安装 Chart 2.3.1添加常用的 chart 仓库 2.3.2…

【springBoot学习篇】springBoot集成mybatis

目录 第一步&#xff1a;新建spring项目的时候&#xff0c;需要勾选mybatis框架和jdbc连接数据库的包 第二步&#xff1a;在resource目录下面的配置文件当中添加以下的内容&#xff1a;配置数据源 第三步&#xff1a;配置实体类 第四步&#xff1a;添加一个对象的增删改查方…

鸿蒙轻内核Kconfig使用笔记

鸿蒙轻内核使用Kconfig进行图形化配置&#xff0c;本文专门讲解下鸿蒙轻内核LiteOS-M和LiteOS-A的图形化配置方法。本文中所涉及的源码&#xff0c;均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_a 、 https://gitee.com/openharmony/kernel_liteos_m 获取。本…

Ubuntu系统设置中文输入法

重新设置超级用户权限(root)密码(非必要) sudo passwd root 需要注意的是Ubuntu的root密码不能少于8个字符 设置成功后输入命令和新的密码即可无需输入sudo启用root命令 su - 更新软件包列表 sudo apt update sudo apt upgrade 安装fcitx5输入法框架 个别情况需要卸载旧的…

EC20通信模块升级失败 Quectel QDLoader 9008

这里写自定义目录标题 usb驱动下载固件和升级软件下载开始升级上述过程升级失败&#xff0c;出现Quectel QDLoader 9008寻找解决方案&#xff0c;事了QPS t不行&#xff0c;最终使用这个Quectel_Customer_FW_Download_Tool软件解决下载链接&#xff1a; 所有下载驱动、固件、软…

【在线OJ】发帖功能前后段代码实现

一、页面布局 二、前端代码 <template><div id"app"><div style"height: 100vh"><div style"display: flex" ><el-input style"width: 95%" v-model"title" placeholder"输入标题"&g…

【Spine学习07】之跑步动作制作思路总结

前几节试着做了待机和走路动画 现在开始尝试做跑步动作 注意跑步动作和走路一样 暂时不需要使用IK约束但是会用到塞贝尔曲线&#xff08;模拟裙子飞起动效&#xff09; 第一步&#xff1a; 先将人物整体斜放置&#xff08;因为人跑步的时候&#xff0c;身体前倾&#xff09; …

『大模型笔记』主成分分析(PCA)解释:简化机器学习中的复杂数据!

主成分分析(PCA)解释:简化机器学习中的复杂数据 文章目录 一. 主成分分析(PCA)解释:简化机器学习中的复杂数据!二. 参考文献一. 主成分分析(PCA)解释:简化机器学习中的复杂数据! 主成分分析(Principal Component Analysis,简称PCA)通过 将大型数据集中的维度减少…

借助ollama实现AI绘画提示词自由,操作简单只需一个节点!

只需要将ollama部署到本地&#xff0c;借助comfyui ollama节点即可给你的Ai绘画提示词插上想象的翅膀。具体看详细步骤&#xff01; 第一步打开ollama官网&#xff1a;https://ollama.com/&#xff0c;并选择models显存太小选择的是llama3\8b参数的instruct-q6_k的这个模型。 运…

blender bpy将顶点颜色转换为UV纹理vertex color to texture

一、关于环境 安装blender的bpy&#xff0c;不需要额外再安装blender软件。在python控制台中直接输入pip install bpy即可。 二、关于代码 本文所给出代码仅为参考&#xff0c;禁止转载和引用&#xff0c;仅供个人学习。 本文所给出的例子是https://download.csdn.net/downl…

手写轮播列表(最新) 轮播图 swiper

el-row版本: <template><div class="container-div" id="app"><div><!-- 头部开始--><div class="top1"><div class="content"><div class="list"><el-row :gutter=&quo…

在ubuntu中恢复误删除的文件

1、安装 TestDisk 在 Ubuntu 上&#xff0c;可以使用以下命令安装 TestDisk&#xff1a; sudo apt-get install testdisk2、查询你删除的文件所在那个分区 #查询分区 df -h #我这里是/dev/sda2 #也可以使用下面命令查看具体哪个分区 lsblk3、查询该分区是什么系统类型 sudo …

【网络编程】基于UDP的服务器端/客户端

UDP可看作是信件邮寄&#xff0c;邮寄过程可能会信件丢失&#xff0c;是一种不可靠的数据传输服务。 但UDP性能更高&#xff0c;实现更加简洁。流控制是区分UDP和TCP的最重要标志。 IP的作用就是让离开主机B的UDP数据包传递给主机B&#xff0c;UDP根据端口号将传到主机的数据包…