Java虚拟机:虚拟机介绍
大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 033 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时,本专栏的所有文章,也都会准备充足的代码示例和完善的知识点梳理,因此也十分适合零基础的小白和要准备工作面试的同学学习。当然,我也会在必要的时候进行相关技术深度的技术解读,相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。
–
在当今的软件开发领域,Java 虚拟机(JVM)扮演着至关重要的角色,它不仅是 Java 语言的运行时环境,也是跨平台应用的基石。理解 JVM 的原理和功能,对 Java 开发者来说至关重要。本篇文章将带你全面了解 JVM 的起源、结构和工作原理,帮助你奠定扎实的基础,为后续深入研究 JVM 的各个方面做好准备。
文章目录
- 1、对于 Java 虚拟机的认知
- 1.1、Java 虚拟机(Jvm) 与 Java 语言的关系
- 1.2、one write run anywhere(一次编写到处运行)
- 1.2.1、C 语言的编译过程
- 1.2.2、如何理解汇编语言
- 1.2.3、C 语言为什么不能跨平台
- 1.2.4、Java 为什么可以跨平台
- 2、Java 虚拟机的基础知识
- 2.1、Java 虚拟机概述
- 2.2、JVM、JRE、JDK的关系
- 2.3、Java 虚拟机的结构组成
1、对于 Java 虚拟机的认知
1.1、Java 虚拟机(Jvm) 与 Java 语言的关系
在我们系统的认识 Java 虚拟机前,我们应该明确一个事实,即:“Java 虚拟机不和包括 Java 在内的任何一种语言绑定,它只与 ‘Class文件’ 这种特定的二进制文件格式所关联,Class 文件中包含了 Java 虚拟机指令集和符号表以及若干其他辅助信息”。
所以 “Java 虚拟机” 这一命名本身有一定的误导性,Java 虚拟机和 Java 语言并不存在必要的联系,将其称作 “Class 文件虚拟机” 可以更适合理解。
Java 在 1997 年发布规范文档的时候,也刻意的将 Java 的规范拆分为《 Java 语言规范(The Java Language Specification)》与 《Java 虚拟机规范(The Java Virtual Machine Specification)》两部分。
Java 语言规范 & Java 虚拟机规范:https://docs.oracle.com/javase/specs/
Java 虚拟机是语言无关性的,作为一个通用的、与机器无关的执行平台,任何其他语言的实现都可以将 Java 虚拟机作为其运行的基础,以 Class 文件作为他们产品的交付媒介。
例如,使用 Java 编译器可以把 Java 代码编译为存储字节码的 Class 文件,使用 JRuby 等其他语言的编译器一样可以把它们的源程序代码编译成 Class 文件。虚拟机丝毫不关心 Class 的来源是什么语言,它与程序语言之间的关系如图所示:
1.2、one write run anywhere(一次编写到处运行)
在我们初次接触 Java 时,都不可不避免的了解到,Java 的一个优势,也是 Java 刚推出时的宣传语:“one write run anywhere(一次编写到处运行)”,在这句话中,突出了 Java 虚拟机核心的思想,Java 虚拟机是与平台无关的,或者说 Java 虚拟机具有平台无关性!
1.2.1、C 语言的编译过程
既然 Java 虚拟机具有平台无关性,那么什么是平台有关性呢,我们先来看一下,C 语言的执行过程:
#include <stdio.h>
int main()
{printf("hello world");return 0;
}
这是一个 C 语言的程序,最终的至执行结果是打印一行 “hello world” 字符串,我们知道,计算机里的世界里只有 “0” 和 “1”,那以上的 C 程序是如何转换为 “0” 和 “1” 的呢?
以上 C 程序的编译过程:
我们分阶段来讨论:
- 首先是 “预处理阶段” :预处理器(cpp)会将头文件(# 开头的行)展开,将宏名替换为字符串,并将注释去掉;
- 接下来是 “编译阶段” :编译器(ccl)将修改后的
.c
文件,翻译为.s
文件,即汇编程序; - 再然后是 “汇编阶段” :汇编器(as)将
.s
文件翻译成.o
文件,这就是机器语言指令,二进制文件; - 在最后是 “链接阶段” :链接器(ld)将
.o
文件中的函数库对应的代码组合到最终目变文件中,这就是.out
文件了。
1.2.2、如何理解汇编语言
作为一个插曲,在这里阐述一下笔者对于汇编语言的理解。
什么是汇编语言,其实就是因为计算机只能识得 “0” 和 “1”,在计算机刚被发明时,科学家们只能通过向计算机输入 0|1 代码的方式(通过穿孔纸带,有孔 1,无孔 0),来运行计算任务,但是这样的效率实在太慢了,所以汇编语言就被发明出来,用于简化程序的编写。
比如计算 1+1
,两个 “1” 数据使用 0x0001
来表示,而 “加” 操作,放在 CPU 中,可以是 0xa90df
(这个是胡乱写的),这个二进制代表的加操作能被计算机识别。而因为这个加操作对于 CPU 来说,编码的 0xa90df
格式是固定的。所以可以直接一个助记符 add
来表示,这样科学家们写程序就方便多了。而这就是汇编程序的由来。因为汇编程序完成之后,可以再有一个专门的程序(就是要上文中所说的汇编器)来把编写的汇编程序编译成 “0” 和 “1”,这样计算机也可以识别了,而汇编语言本身也方便了程序的编写和阅读。
编写汇编比直接编写二进制方便高效了太多。但是随着计算任务的复杂,程序的规模越来越庞大,使用汇编程序也很累啊,那么是否有更简单的方式呢?所以科学家们发明了高级语言(比如 C,lisp 等),在编写程序的时候,使用 C。语言等编写,然后再使用编译器将 C 语言程序翻译成汇编程序,汇编程序再使用汇编器编译成 “0” 和 “1”,这样,CPU 能识别的东西没有变化,但是对于编写程序的人,确实方便了很多。
通过以上的描述,我们就知道了高级语言的大概由来。也明白了我们所编写的各种高级语言,到了最后,其实都是转化为二进制执行。
1.2.3、C 语言为什么不能跨平台
在对汇编语言再一次理解之后,我们回到正题,即为什么 C 语言不具备平台无关性,或者说为什么 C 语言为什么不能跨平台。
直接二进制格式的程序,我们称之为本地机器码(native code)。而类似那些 add
之类的助记符,以及汇编的编写格式或标准,我们称之为指令集。
但是问题的关键来了。不同公司所生产的 CPU 芯片。他们所使用的指令集不同啊,这种芯片设计的事情,又不像 TCP/IP 协议那样,有国际统一的标准,甚至像 Intel 所代表的复杂指令集,和 ARM 为代表的精简指令集,它们指令集的设计思路就是不一样的。
所以我们 C 语言最后编译出来的的二进制文件,不同的 CPU 上识别的意义是完全不同的。
此外,还有一种场景,就是一段 C 语言的程序,我们编写一个 .c
的文件后,将其拿到另外一个操作系统|CPU 平台去执行,是否会成功呢?成功了之后那么是否可以说明 C 语言具有跨平台性呢,很多人存在着不同的看法,对此,笔者是这样认为的:
- C 语言并非不能跨平台(CPU 或者操作系统),准确的说是 C 语言编译出的程序无法二进制跨平台;
- 不同环境下,C 语言的标准有差别,比如不同平台的 int 类型可能是 16 位表示也可能是 32 位表示,但笔者认为这种情况是可以有多种方式去规避的,随意最终的结论还是 C 语言不能跨平台是特指二进制跨平台。
那有没有一种办法,能够让高级语言实现(二进制)跨平台的运行呢?
思考实际编程中的一个场景,我们前端需要处理的某个数据是 A 格式,但是后台只能提供B格式的数据,那我们怎么办?很简单啊。写个接口,把 B。格式转化为 A 格式。这就是设计模式当中的适配器设计模式。
关于跨平台也是一样的道理。CPU 的指令集不同, 不同平台编译出来的结果格式都不同,那么我们可以在各个平台上运行虚拟机,然后我们制定某种编译结果的输出格式,我们的输出了某种格式的结果,直接在虚拟机上运行。 这就是 Java 采取的方式。
1.2.4、Java 为什么可以跨平台
这是 Java 版本的 “Hello World”:
public static void main(String[] args) {System.out.println("Hello World!");
}
这段 Java 程序编译出来的结果是 hello.class
,换句话说,它输出的结果是 Class 文件格式(也叫字节码存储格式)。
这其实就是 Java 虚拟机定义的二进制格式,这种我们称之为字节码(ByteCode),是 Java 虚拟机所能运行的格式。类似本地机器码可以反编译成汇编,这种二进制也可以反编译成更容易阅读的格式。
而各个平台的 Java 虚拟机 是不同的。但是我们编写的 Java 程序 统一编译成特定格式的 Class 文件格式,然后 Class 文件可以在各个不同平台的 Java 虚拟机上运行,当然运行结果肯定也是一致的,至于各个不同平台之间的差异,这是那些编写 Java 虚拟机的人去考虑的事情。
通过这种方式,我们的 Java 程序就实现了跨平台。
2、Java 虚拟机的基础知识
2.1、Java 虚拟机概述
Java 虚拟机(英语:Java Virtual Machine,缩写:JVM),一种能够执行 Java 字节码(Class 文件)的虚拟机,以堆栈结构机器来进行实做。最早由 Sun 公司所研发并实现第一个实现版本,是 Java 平台的一部分,能够执行以 Java 语言所写的软件程序。
Java 虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。通过对中央处理器(CPU)所执行的软件实现,实现能执行编译过的 Java 程序码(Applet 与应用程序)。
作为一种编程语言的虚拟机,实际上不只是专用于 Java 语言,只要生成的编译文件符合 JVM 对加载编译文件格式要求,任何语言都可以由 JVM 编译运行。此外,除了甲骨文,也有其他开源或闭源的实现。
2.2、JVM、JRE、JDK的关系
JVM 是 Java 程序能够运行的核心。但需要注意,JVM 自己什么也干不了,你需要给它提供生产原料(Class 文件)。 仅仅是 JVM,是无法完成一次编译,处处运行的。它需要一个基本的类库,比如怎么操作文件、怎么连接网络等。
而 Java 体系很慷慨,会一次性将 JVM 运行所需的类库都传递给它。JVM 标准加上实现的一大堆基础类库,就组成了 Java 的运行时环境,也就是我们常说的 JRE。
对于 JDK 来说,就更庞大了一些。除了JRE,JDK还提供了一些非常好用的小工具,比如 javac、java、jar 等。它是 Java 开发的核心。 我们也可以看下 JDK 的全拼,JavaDevelopmentKit。
JVM、JRE、JDK 它们三者之间的关系,可以用一个包含关系表示:
2.3、Java 虚拟机的结构组成
Java 虚拟机整体组成可分为四个部分:类加载器(Class Loader)、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)、本地库接口(Native Interface)
- 类加载器:负责从字节码 Class 文件中,加载 Class 信息到运行时数据区的方法区;
- 运行时数据区:存放 Jvm 在执行 Java 程序时相关数据的区域;
- 执行引擎:将字节码翻译成底层系统指令再交由 CPU 去执行;
- 本地库接口:执行过程中可能需要调用到其他语言(比如 C 语言)的本地接口。
Ps:Javac 是收录于 Jdk 中的 Java 语言编译器。该工具可以将 .java
源文件编译为 Class 文件(.class
文件)。
在程序被执行之前,Java 前, Java 代码会被先转换成字节码 Class 文件,Jvm 首先通过一定的方式使用「类加载器」把字节码文件加载到内存中「运行时数据区」,而字节码文件是 Jvm 提供的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器「执行引擎」将字节码翻译成底层系统指令再交由 CPU 去执行,而这个过程中需要调用其他语言的接口「本地库接口」,来实现整个程序的功能,这就是这 4 个主要组成部分的职责与功能。
相关文章:

Java虚拟机:虚拟机介绍
大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 033 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进…...
硬件面试经典 100 题(31~40 题)CRE4
31、多级放大电路的级间耦合方式有哪几种?哪种耦合方式的电路零点偏移最严重?哪种耦合方式可以实现阻抗变换? 有三种耦合方式:直接耦合、阻容耦合、变压器耦合。直接耦合的电路零点漂移最严重,变压器耦合的电路可以实现…...

ReactNative笔记(自用)
环境 ios更换gem镜像源: 查看当前源: gem sources -l 移除默认源: gem sources --remove https://rubygems.org/。添加新的源: 添加 Ruby China 的镜像源: gem source -a https://gems.ruby-china.com/或者添加其他镜像源。 清华大学的gem源: htt…...
嵌入式八股-面试30题(20240812)
TCP和UDP的区别是什么? **TCP(Transmission Control Protocol)**是面向连接的协议,提供可靠的、顺序的数据传输。它通过三次握手建立连接,并在数据传输过程中使用确认和重传机制来确保数据的正确性。TCP还支持流量控制和拥塞控制…...
单一职责原则(SRP)
目录 1、定义 2、优点 3、原则的重要性 4、 示例 5、注意事项 单一职责原则(Single Responsibility Principle, SRP)是面向对象设计中的一项重要原则,属于 SOLID 原则之一。它的核心思想是:一个类应该只有一个引起它变化的原因&am…...

骨传导耳机怎么选?分享五款资深用户都说好的骨传导耳机!
在追求健康生活的道路上,运动健身已成为一种时尚潮流,而音乐则是这场潮流中不可或缺的催化剂。然而,传统耳机在运动场景下的局限性日益凸显,难以满足运动者对自由与舒适的双重追求。正是基于这样的市场需求,骨传导耳机…...
【计算机网络——分组延时,丢失,吞吐量】
处理延时:1检查分组首部信息,决定将该分组导向何处所需时间。2检查比特级别的差错所需时间:分析这个分组是否出错,目标IP地址字段提取出来,查路由表……。 传播延时和传输延时:传输延时就是分组到链路所需…...

使用1panel 申请证书配置雷池站点
1.创建测试站点 2.使用1panel申请测试站点的自签名证书 ps:雷池支持自签的证书 关于如果选择网站的SSL证书 百度搜索 看起来是证书的问题 调整了参数重新申请一个证书上传 注意,如果文件上传错了,雷池会报错,如下图 再次访问配…...

4章7节:用R做数据重塑,数据去重和数据的匹配
在数据科学的分析流程中,数据重塑是一项非常重要的操作。数据的重塑通常指将数据从一种形式转换为另一种形式,以满足后续分析的需求。R语言提供了丰富的工具和函数来帮助用户高效地进行数据重塑操作。本文中,我们将深入探讨数据重塑的概念及其…...

大数据面试SQL(七):累加刚好超过各省GDP40%的地市名称
文章目录 累加刚好超过各省GDP40%的地市名称 一、题目 二、分析 三、SQL实战 四、样例数据参考 累加刚好超过各省GDP40%的地市名称 一、题目 现有各省地级市的gdp数据,求从高到低累加刚好超过各省GDP40%的地市名称,临界地市也需要。 例如: 浙江省…...

建议收藏!这4款设计师常用的素材管理软件,助你工作效率翻倍!
嘿,设计师们!你是否还在为那一堆堆散乱的素材头疼?每次灵感来袭,却要花费大量时间在层层文件夹中苦苦搜寻?别急,今天我就来给大家推荐4款超给力的素材管理软件,它们不仅能帮你轻松整理素材库&am…...
用于NLP领域的排序模型最佳实践
在自然语言处理(NLP)领域,用于排序任务的模型通常是指那些能够对文本进行排序、比较或评估其相关性的模型。这些模型可以应用于诸如文档排序、句子排序、问答系统中的答案排序等多种场景。在当前的研究和发展中,基于深度学习的方法…...
域名未备案的支付平台遭遇大攻击怎么办
域名未备案的支付平台遭遇大攻击怎么办?在当今数字化时代,支付平台的安全与稳定性是保障业务连续性和用户信任的关键。然而,对于因域名未备案而面临法律风险的支付平台来说,其安全挑战更为严峻。当这类平台遭遇大规模的网络攻击&a…...

【NI-DAQmx入门】LabVIEW数据采集基础应用程序框架
对于可管理规模的 LabVIEW 程序,分析现有程序或设计新程序的方法通常是从整体到具体,即从高级到低级的分析和设计。从一开始就直接深入细节可能会效率较低。 在设计阶段,开发人员首先将程序垂直划分为几个层级。从最顶层开始,他们…...
海山数据库(He3DB)源码详解:CommitTransaction函数源码详解
文章目录 海山数据库(He3DB)源码详解:CommitTransaction函数1. 执行条件2. 执行过程2.1 获取当前节点状态:2.2 检查当前状态:2.3 预提交处理:2.4 提交处理:2.5 释放资源:2.6 提交事务: 作者介绍…...

【网络】传输层TCP协议的报头和传输机制
目录 引言 报头和有效载荷 确认应答机制 捎带应答机制 超时重传机制 排序和去重 连接管理机制 个人主页:东洛的克莱斯韦克-CSDN博客 引言 TCP是传输层协议,全称传输控制协议。TCP报头中有丰富的字段以及协议本身会制定完善的策略来保证网络传输的…...
【活动报名】打造编程学习“知识宝库”:高效笔记记录与整理指南
如何高效记录并整理编程学习笔记? 在编程学习的旅程中,拥有一套高效的笔记记录和整理方法至关重要。以下将从三个方向为您详细介绍如何打造属于自己的编程学习“知识宝库”。 方向一:笔记工具选择 选择合适的笔记工具是高效记录编程学习笔记…...

使用Arduino IDE生成带有bootloader的烧录文件
使用Arduino IDE生成bin(烧录)文件 1、在“项目”中,选择“导出已编译的二进制文件” 2、在工程目录中,会出现“build”文件夹 3、在build文件夹中,有hex文件,以及包含bootloader的bin和hex文件 bin和h…...

搭建高可用OpenStack(Queen版)集群(九)之部署nova计算节点
一、搭建高可用OpenStack(Queen版)集群之部署计算节点 一、部署nova 1、安装nova-compute 在全部计算节点安装nova-compute服务 yum install python-openstackclient openstack-utils openstack-selinux -y yum install openstack-nova-compute -y 若yu…...
C# 字符串扩展方法
功能 1.判断一个字符串是否为null或者空字符串 2.判断一个字符串是否为null或者空白字符 3.判断一个字符串是否为数字 4.判断一个字符串是否为邮件 5.判断一个字符串是否为字母加数字 6.判断一个字符串是否为手机号码 7.判断一个字符串是否为电话号码 8.判断一个字符串是否为网…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...