java(JVM)

news2024/11/23 3:18:36

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.coloradmin.cn/o/1829264.html

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

相关文章

通过命令行启动MySQL

通过命令行启动MySQL 右击,选择管理员运行 停止MySQL net stop你的服务名称 net stop MySQL启动MySQL net start你的服务名称 net start MySQL

实战项目: 负载均衡

0. 前言 这个项目使用了前后端,实现一个丐版的LeetCode刷题网站,并根据每台主机的实际情况,选择对应的主机,负载均衡的调度 0.1 所用技术与开发环境 所用技术: C STL 标准库 Boost 准标准库 ( 字符串切割 ) cpp- httplib 第三方开源网络库 ctemplate 第三方开源前端网…

pikachu中pkxss数据库怎么创建

在用小皮时候,只是知道个pikachu这个数据库,跟着视频看人家用pkxss数据库,自己也想用,查看了很多资料,又蒙又查,终于明白怎么弄,特此传授经验 图像中画横线的就是平常怎么创建数据库的&#xff…

HP惠普暗影精灵10 OMEN Gaming Laptop 16-wf1xxx原厂Win11系统镜像下载

惠普hp暗影精灵10笔记本电脑16-wf1000TX原装出厂Windows11,恢复开箱状态oem预装系统安装包,带恢复重置还原 适用型号:16-wf1xxx 16-wf1000TX,16-wf1023TX,16-wf1024TX,16-wf1025TX, 16-wf1026TX,16-wf1027TX,16-wf1028TX,16-wf1029TX, 16-wf1030TX,16-…

C++ 算法教程

归并排序 #include<iostream> using namespace std; template <class T> void Merge(T data[],int start,int mid,int end) {int len1 mid - start 1, len2 end - mid;int i, j, k;T* left new int[len1];T* right new int[len2];for (i 0; i < len1; i)…

爆火的治愈系插画工具又来了,额度居然有18w,根本花不完?

AI治愈插画又又又来了 今天给大家推荐一款完全免费的软件&#xff0c;用过的人都说好&#xff01; 先来看看我生成的图 制作过程非常简单&#xff0c;输入你想要生成的画面咒语。 工具地址&#xff1a;https://www.qiyuai.net/ 模型目前有两种 我上面的图就是用的第一种通用…

Shell 学习笔记 - 导读 + 变量定义

初识 Shell 本章学习目标 了解什么是 Shell了解 Shell 的版本及用途掌握 Shell 变量的用法 导读&#xff08; 了解 \color{cyan}{了解} 了解&#xff09; 现在的人们使用的操作系统&#xff08;Windows、Android、iOS 等&#xff09;都带有图形化界面&#xff0c;简单直观&…

秋招突击——第五弹——Java的SSN框架快速入门——SpringBoot的使用

文章目录 引言SpringBoot简介入门案例SpringBoot项目快速启动 SpringBoot概述起步依赖辅助功能 基础配置配置文件格式基础配置Yaml格式书写Yaml格式读取多环境开发多环境启动命令格式多环境开发兼容问题配置文件分类 整合第三方技术整合Junit基于SpringBoot实现SSM整合Springbo…

axure9设置组件自适应浏览器大小

问题&#xff1a;预览时不展示下方的滚动条 方法一&#xff1a;转化为动态面板 1.在页面上创建一个矩形 2.右键-转化为动态面板 3.双击进入动态面板设置 4.设置动态面板矩形的颜色 5.删除原来的矩形 6.关闭动态面板&#xff0c;点击预览 7.此时可以发现底部没有滚动条了 方法…

23 华三(自动获取的IP地址)

华三交换机 DHCP 配置 #version 7.1.070, Alpha 7170 //设备的版本信息 #sysname sw1 //修改设备的名字 #irf mac-address persistent timerirf auto-update enableundo irf link-delayirf member 1 priority 1#dhcp enable //开启DHCP 服务dhcp server forbidden-ip 192.168.…

PDFFactoryFinePrint软件安装包下载+详细安装教程

简介&#xff1a; pdfFactory Pro(虚拟打印机)是一个无须 Acrobat 创建 Adobe PDF 文件的打印机驱动程序。 pdffactory pro虚拟打印机提供了比其他程序提供得更简单、更有效率和更少的花费的创建 PDF 文件的解决方案。用于需要安全的 PDF(法律文档、公司信息等)和其他高级功能…

Vue53-Todo-list案例

一、需求&#xff1a; 二、组件的划分&#xff1a;按照功能划分 组件起名&#xff0c;不要和html内置元素重名&#xff01; Vue鼓励组件名用多个单词。 三、组件化编码流程 3-1、实现静态组件 将各个组件的基本框架写好&#xff0c;并在App.vue文件中进行引入和注册。 将已有…

HTTP协议 快速入门

http概述 无状态性&#xff1a;HTTP是一个无状态协议&#xff0c;这意味着服务器不会在请求之间保存任何会话信息。每个请求都是独立的&#xff0c;服务器不会记住之前的请求。 请求-响应模型&#xff1a;HTTP通信是基于客户端发送请求和服务器返回响应的模型。客户端&#xf…

ffmpeg解封装rtsp并录制视频-(1)解封装rtsp断网或摄像机重启后自动重连处理

头文件&#xff1a; xtools.h #pragma once #include <thread> #include <iostream> #include <mutex> //日志级别 DEBUG INFO ERROR FATAL enum XLogLevel {XLOG_TYPE_DEBUG,XLOG_TYPE_INFO,XLOG_TPYE_ERROR,XLOG_TYPE_FATAL }; #define LOG_MIN_LEVEL XLO…

【Android】基于webView打造富文本编辑器(H5)

目录 前言一、实现效果二、具体实现1. 导入网页资源2. 页面设计3. 功能调用4. 完整代码 总结 前言 HTML5是构建Web内容的一种语言描述方式。HTML5是Web中核心语言HTML的规范&#xff0c;用户使用任何手段进行网页浏览时看到的内容原本都是HTML格式的&#xff0c;在浏览器中通过…

C语言实现动态栈

#include<stdio.h> #include<stdlib.h> #include<stdbool.h>// 每一个节点的数据类型 typedef struct Node {int data;struct Node * pNext; }NODE, * PNODE; // NODE等价 struct Node PNODE等价于 struct Node *// 栈 typedef struct Stack {PNODE pTop;P…

如何判断一个js对象是否存在循环引用

一、背景 在前端JSON.stringfy是我们常用的一个方法&#xff0c;可以将一个对象序列化。 例如将如下对象序列化 const person { name: kalory, age:18}JSON.stringfy(person) // 结果 {"name":"kalory","age":18}将一个数组序列化const arr …

Gson的常见用法

一引入依赖 <!-- json解析的工具包 --> <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version> </dependency> <!-- 主要为了代码简洁和日志打印 --> <…

天翼云认证专家解决方案架构师(理论)

1.某大型互联网公司为了提升应用程序和基础设施的稳定性&#xff0c;计划引入自动化监控工具。以下哪些工具可以满足公司的需求? A.Grafana B.Nagios C.Prometheus D.Jenkins 2.天翼智能边缘云ECX是位于网络边缘位置的云&#xff0c;兼具云和CDN的特性&#xff0c;将计算、存…

Windows11安装并使用Gstreamer-1.0

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、下载二、使用步骤1.安装2.命令行测试 总结 前言 Gstreamer这个工具的重要性就不用多说了吧&#xff0c;在一些视频播放和解码领域大放异彩。以前更多的是在…