JVM 虚拟机(一)导学与字节码文件组成

news2024/11/24 13:07:49

一、实战 JVM - 基础篇

初识 JVM

什么是 JVM?

Java Virtual Machine(JVM),中文翻译为 Java 虚拟机

image.png

JVM 的功能

  1. 解释和运行:对字节码文件中的指令进行实施的解释成机器码,让计算机执行。
  2. 自动为对象和方法分配内存:自动的垃圾回收机制,不用自己编写代码进行垃圾回收。
  3. 即时编译:对热点代码进行优化,提升执行的效率。
即时编译

image.png

因为 Java 虚拟机比起诸如 C 或 C ++ 多了一个**解释**功能,这个功能可以支持 Java 语言的**跨平台**的特性,可以将语言转化为对应的系统的机械码,对应的,比起 C 和 C++ 性能要差一些。

跨平台性:
如果一个编程语言没有跨平台的特性,需要在每个不同的操作系统上进行适配才能让程序在该系统上运行。这意味着针对每个操作系统,需要重新编写或修改程序的部分代码,以使其能够与该操作系统兼容。
举例来说,假设某个编程语言的代码只能在特定操作系统(比如只能在 Windows 上运行)上执行,那么如果希望这段代码能在其他操作系统(如 macOS、Linux 等)上运行,就需要对其进行适配或重写,以使其能够兼容其他操作系统的特性和功能。
这种情况下,开发者需要针对不同的操作系统编写特定版本的代码或者使用特定的工具来进行跨平台适配,以确保程序能够在不同的操作系统上运行。这也是为什么具备跨平台能力的编程语言和工具(比如 Java、Python 等)受到青睐,因为它们可以使开发者编写一次代码,然后在不同操作系统上运行而无需针对每个操作系统进行修改。

image.png
当 Java 虚拟机发现某一段代码是热点代码,即这段代码会在后面的程序中多次使用的时候,JVM 会将这个代码解释并优化成机械码,然后将其保存在内存中,方便之后的调用。
上述的操作使得 Java 虚拟机实现了即时编译的功能(JIT),能保证性能接近 C 和 C++ 甚至在特定的情况下超越。

常见的 JVM

image.png

Java 虚拟机规范
  • 《 Java 虚拟机规范 》由 Oracle 指定,内容包含了虚拟机在设计和实现的时候需要遵守的规范,主要包含 class 字节码文件的定义、类和接口的加载和初始化、指令集等内容。
  • 这个规范是对虚拟机的要求,但不一定是 Java 虚拟机,其他语言生成的 class 字节码文件之上也可以运行虚拟机。
HotSpot 发展史

image.png

字节码文件详解

Java 虚拟机的组成

image.png
JVM(Java Virtual Machine,Java 虚拟机)是运行 Java 字节码的虚拟计算机,它由多个组成部分构成,包括以下主要组件:

  1. 类加载器(Class Loader):负责将类的字节码加载到 JVM 中。它将类文件加载到内存,并生成相应的 Class 对象,用于在运行时创建实例、访问字段和调用方法。
  2. 运行时数据区域(Runtime Data Areas):包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。
    1. 方法区(Method Area):存储类信息、常量、静态变量等数据。
    2. 堆(Heap):存放对象实例。
    3. 虚拟机栈(Java Virtual Machine Stacks):存储方法调用的局部变量、部分结果和返回值。
    4. 本地方法栈(Native Method Stack):为 Java 方法调用 Native 方法(非 Java 语言编写的方法)服务。
    5. 程序计数器(Program Counter):记录当前线程执行的字节码指令地址。
  3. 执行引擎(Execution Engine):负责执行编译后的字节码。包括解释器和 JIT 编译器。解释器逐行解释字节码,而 JIT 编译器将热点代码(频繁执行的代码)编译为本地机器代码以提高执行效率。
  4. 本地方法接口(Native Interface):允许 Java 代码调用本地库中的方法。
  5. 本地库接口(Native Libraries):Java 虚拟机使用的本地库,提供与操作系统交互的能力。

其中的本地方法指的是使用本地语言(如 C 或 C++)编写的方法,通过这些方法,虚拟机可以实现与操作系统或者硬件之间的交互,通过本地方法,虚拟机可以实现如下的功能:

  1. 操作系统交互:Java 中的一些功能需要直接与操作系统进行交互,比如文件操作、网络通信、图形界面等。为了实现这些功能,Java 使用本地方法调用操作系统提供的相关功能。
  2. 性能优化:某些对性能要求极高的任务可能通过本地方法来实现,因为本地语言(如C或C++)可以更接近底层硬件,可以更高效地执行某些计算密集型操作。
  3. 特定硬件功能:有时,需要访问特定硬件设备或执行底层操作,这时候本地方法可以提供直接的接口,以便与硬件交互。

字节码文件

以正确的方式打开文件

字节码文件保存了源代码编译之后的内容,以二进制的方式存储,无法直接用记事本打开阅读

jclasslib:https://github.com/ingokegel/jclasslib/releases
同样的,可以选择 IDEA 插件,也叫做 jclasslib,后期主要使用这个插件进行操作
字节码文件的五个组成部分

  1. 基础信息:魔数、字节码文件对应的 Java 版本号,访问表示(public、final 等等)父类和接口
  2. 常量池:保存了字符串常量、类或接口名、字段名主要在字节码指令中使用
  3. 字段:当前类或者接口声明的字段信息
  4. 方法:当前类或者接口声明的方法信息的字节码指令
  5. 属性:类的属性,比如源码的文件名、内部类的列表等等

详解字节码文件的组成

image.png
这里我们主要说基本信息、常量池和方法

基本信息

魔数、字节码文件对应的 Java 版本号,访问表示(public、final 等等)父类和接口

  1. 魔数

魔数通常用于识别特定格式的文件,比如图像文件(如JPEG、PNG)、可执行文件(如ELF、PE)或归档文件(如ZIP、RAR)。

  • 文件时无法通过文件的拓展名来确定文件的类型的,文件的拓展名可以随意的修改,不影响文件的内容
  • 软件使用文件的头几个字节(文件头)去验证文件的类型,如果文件不符合着各种类型就会报错
  • Java 字节码文件中,将文件头称为 magic 魔数

我们通过查看文件的十六进制编码就可以在开头看到这些标识。
image.png

  1. 主副版本号

要了解主副版本号,我们首先来回顾一下 JDK(Java Development Environment)
JDK 主要包含了下面这些内容

  • JRE(Java Runtime Environment): JDK 中包含了 JRE 的所有内容,因此 JDK 也可以用作运行 Java 程序的环境。JRE 包括 Java 虚拟机(JVM)和运行 Java 应用程序所需的核心类库
  • Java 命令行工具: JDK 提供了一系列的命令行工具,用于编译、调试、执行和分析 Java 应用程序。比如 java(运行 Java 程序)、javac(编译 Java 程序)、javadoc(生成 API 文档)、jdb(Java 调试器)等。
  • Java API 和类库: JDK 包含了大量的 Java API 和类库,提供了丰富的功能和工具,用于开发各种类型的应用程序。这些类库包括 Java 核心类库、I/O、网络、集合框架、GUI(Swing、JavaFX)、安全性等各个领域的支持。
  • 开发工具(IDE)支持: JDK 可与各种 Java 开发工具(如 Eclipse、NetBeans、IntelliJ IDEA 等)集成使用,提供开发和调试 Java 应用程序的环境
  • 调试器和性能分析工具: JDK 提供了调试器(jdb)和一系列性能分析工具,用于调试和分析 Java 应用程序的性能问题,帮助开发人员诊断和解决代码中的错误和性能瓶颈。
  • JavaFX 和其他扩展: JDK 中还包括 JavaFX 等扩展技术,用于开发富客户端应用程序。此外,JDK 也支持其他扩展和工具,如 Java Mission Control(JMC)等。

我们编写的代码会通过 JDK 中的编译工具编译成字节码文件之后交给虚拟机运行,这个编译过程会首先检查我们编写的代码和当前 JDK 的版本是否兼容。

  • 判断当前字节码文件的版本和运行时的 JDK 是否兼容,

image.png
我们在开发中可能会遇到下面的报错:
比如我们引用别人的库的时候,调用其中的 class 文件如果和我们当前运行的环境不匹配的
image.png
通过上面的 主版本号 - 44 的公式,我们可以看出这个需要的是 JDK 8 但我们的环境是 JDK 6,这时候我们有两种解决方法:

  1. 升级 JDK 版本
  2. 降低我们依赖的版本号或者更换依赖

显然后一种最稳健,不会对项目中的其他代码产生影响。

常量池

为了避免相同的内容的重复定义,节省空间
Java中的常量池主要分为两种:

  1. 编译期常量池(Compile-Time Constant Pool): 这是在编译期间确定的常量池。它包含类文件中的常量池表(Constant Pool Table),存储着类、方法、接口等的符号引用、字面量常量等。
  2. 运行时常量池(Runtime Constant Pool): 这是JVM在运行时动态生成的常量池。它是方法区的一部分,用于存放在编译期无法确定的常量,比如使用String类的intern()方法在运行时将字符串对象添加到常量池中。

Java常量池的使用方式和注意事项:

  • 字符串常量池:Java中的字符串常量池是String类中特有的,它存储着所有的字符串字面量。当创建字符串常量时,如果常量池中已经存在相同内容的字符串,则不会再创建新的对象,而是直接引用已存在的字符串对象。
  • 使用final关键字:通过使用final关键字定义的常量会被优化,并在编译时被放入常量池中。这些值在运行时无法修改。
  • 自动装箱:在使用自动装箱时,如果值在-128到127之间,Java会将其缓存起来,使得对象引用指向同一个常量。
  • 字符串的intern()方法:调用字符串的intern()方法会将字符串对象添加到常量池中(如果池中已经存在相同内容的字符串,则返回池中的对象引用)。
  • 编译器优化:编译器会对一些简单的表达式进行计算,并在编译期间将计算结果存入常量池中。

比如看下面这个例子,我们如果写了很多相同的字符串,如果字节码文件采取右边的存储方法,光是存储这些字符串就占了大量的内存,为了节省内存的开支,JVM 虚拟机有一块单独的内存,用于存储被编译器或运行时系统使用的常量和字面量。它包含了编译时生成的各种字面量和符号引用。
image.png
下面我们来利用 jclasslib 来观察一下常量池的机制,先编写一个简单代码示例

package com.kq.Basic;

/**
 * 演示常量池的特点
 */
public class ConstantPools {
    String a = "abc";
    String b = "abc";
}

image.png
编译后使用 jclasslib 打开
image.png
image.png
我们打开就可以发现一个指向的是字符串池子中的对象,一个是字符串常量池中的具体元素
image.png
这时候查看一下这段程序的执行流程,在方法区域,观察字节码文件

0 aload_0        // 将当前对象的引用加载到操作数栈上
1 invokespecial #1 // 调用超类构造方法

4 aload_0        // 将当前对象的引用加载到操作数栈上
5 ldc #7 <abc>   // 将字符串常量"abc"加载到操作数栈上
7 putfield #9    // 将操作数栈上的"abc"赋值给当前对象的字段
                 // (此处 #9 是字段的索引或标识)

10 aload_0       // 将当前对象的引用加载到操作数栈上
11 ldc #7 <abc>  // 将字符串常量"abc"加载到操作数栈上
13 putfield #15  // 将操作数栈上的"abc"赋值给当前对象的字段
                 // (此处 #15 是字段的索引或标识)

16 return        // 返回

注意看这一步 将操作数栈上的"abc"赋值给当前对象的字段 我们通过地址就会发现是我们上面提到的 #7 对象,这时候 a 指向的就是字符串常量池中的对象。

image.png
我们顺着这个地址过去,发现是指向的这个对象,这个对象又指向了字符串常量池的另一个对象
image.png,那为什么不直接使得指向的这个对象就是字符串呢,还要多一个中间的步骤?

字符串常量池是为了节省内存并提高性能而设计的特殊机制,主要原因如下:

  • 字符串频繁被使用:在许多应用中,字符串是经常使用的数据类型之一。由于字符串的不变性质,它们很容易被共享和重复使用,因此将字符串放入共享的常量池中可以减少内存占用。
  • 字符串不变性:字符串在 Java 中是不可变的,即一旦创建就不能被修改。如果将字符串直接放入常量池中,可以保证字符串的不可变性,避免了在运行时更改字符串的可能性。
  • 字符串比较效率:使用字符串常量池可以加快字符串的比较速度。由于字符串常量池中的字符串是唯一的,可以通过比较引用地址来进行比较,提高了比较的效率。
  • 其他类型的常量(例如整数、浮点数、布尔值等)在 Java 中也有常量池,但并不像字符串常量池那样明确,因为它们通常不会像字符串那样频繁地被使用。字符串常量池的设计是为了针对字符串这种特殊的不变性和频繁使用性质而提出的一种优化策略。
方法

当前类或者接口声明的方法信息,这个部分放在下个博客中详细说明。

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

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

相关文章

PyTorch机器学习与深度学习实践技术应用

近年来&#xff0c;随着AlphaGo、无人驾驶汽车、医学影像智慧辅助诊疗、ImageNet竞赛等热点事件的发生&#xff0c;人工智能迎来了新一轮的发展浪潮。尤其是深度学习技术&#xff0c;在许多行业都取得了颠覆性的成果。另外&#xff0c;近年来&#xff0c;Pytorch深度学习框架受…

不会代码(零基础)学语音开发(语音播报板载双按键状态)

这个例程实现语音播报VDB-150S语音开发板板载的按键开关SW1、SW2的按下情况。 语音开发板将板载的按键开关SW1、SW2的一端都接到了GND端&#xff0c;另一端分别连接到语音模块的GPIO_B0、GPIO_B1引脚&#xff0c;当按下SW1时GPIO_B0引脚会输入低电平&#xff0c;当按下SW2时GP…

Hadoop学习笔记(HDP)-Part.19 安装Kafka

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

pyqt5+QWebEngineView+pdfjs+win32print实现pdf文件的预览、打印

一、pdf显示逻辑 import sys from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgetsPDFJS = file:///pdfjs-1.9.426-dist/web/viewer.html # PDFJS = file:///usr/share/pdf.js/web/viewer.html PDF = file:///D:/Code/report.pdfclass Window(QtWebEngineWidgets.QWebEng…

使用 MITRE ATTCK® 框架缓解网络安全威胁

什么是MITRE ATT&CK框架 MITRE Adversarial Tactics&#xff0c; Techniques&#xff0c; and Common Knowledge&#xff08;ATT&CK&#xff09;是一个威胁建模框架&#xff0c;用于对攻击者用来入侵企业、云和工业控制系统&#xff08;ICS&#xff09;并发起网络攻击…

在交易中价差遇上对冲,fpmarkets操作得当,盈利必不可少

想不到吧&#xff01;fpmarkets发现在交易中价差遇上对冲&#xff0c;只要操作得当&#xff0c;盈利必不可少。 下面我们就通过实践证明这个认知&#xff0c;我们大家都知道&#xff0c;交易可以分为两种方式:激进的和保守的。从定义中可以清楚地看出&#xff0c;一种方式风险较…

机器学习实验一:线性回归

系列文章目录 机器学习实验一&#xff1a;线性回归机器学习实验二&#xff1a;决策树模型机器学习实验三&#xff1a;支持向量机模型机器学习实验四&#xff1a;贝叶斯分类器机器学习实验五&#xff1a;集成学习机器学习实验六&#xff1a;聚类 文章目录 系列文章目录一、实验…

【python】使用pipenv创建虚拟环境进行打包

文章目录 一、pipenv 介绍二、快速上手使用pipenv2.1 安装pipenv2.2 创建虚拟环境2.3 激活环境2.4 虚拟环境中安装项目依赖包2.5 检查项目在虚拟环境中是否能正常运行2.6 打包项目2.7 删除虚拟环境 起因: 本地安装的模块太多,使用pyinstaller打包,会把许多无关模块打包进去&…

“站立的山川——周扬波 中国山水画创作新表达系列画展”将亮相深圳东方美术馆

展览信息 站立的山川——周扬波 中国山水画创作新表达系列画展 中国文学艺术界联合会青年文艺创作扶持计划项目 学术主持 陈明 学术顾问 何加林 主办单位 中国文化艺术发展促进会水墨画专业委员会 承办单位 深圳东方美术馆 协办单位 李可染画院 深圳东方银座酒店 …

微信小程序pc端宽高:默认宽高为1024*812,全屏宽高为1920*1032

最近开发调试pc端小程序&#xff0c;想知道默认打开和全屏这两种情况下的小程序宽高&#xff0c;发现了一种方法&#xff1a; 真机运行pc端小程序&#xff0c;点击devTools 在控制台直接打印window对象&#xff0c;可以获取到pc端默认屏幕宽高为1024*812&#xff0c;全屏pc端小…

微信小程序怎么做店铺

随着移动互联网的快速发展&#xff0c;越来越多的企业和个人开始在微信小程序上开设店铺&#xff0c;以实现线上销售。那么微信小程序怎么做店铺呢&#xff1f;下面给大家分享下步骤指南。 首先需要明确你的店铺定位和目标用户群体。这一步骤非常关键&#xff0c;因为它将决定你…

Qt + MySQL(简单的增删改查)

Qt编译MySql插件教程 QSqlDatabase 静态函数 1.drivers()&#xff0c;得到可以使用的数据库驱动名字的集合 [static] QStringList QSqlDatabase::drivers();2.addDatabase()&#xff0c;添加一个数据库实例 [static] QSqlDatabase QSqlDatabase::addDatabase(const QStrin…

抖音商家电话采集如何用爬虫软件实现

随着互联网的发展&#xff0c;越来越多的商家开始在抖音上开设店铺。本文将介绍如何用爬虫软件实现抖音商家电话采集。 第一步&#xff1a;安装Python爬虫框架 Python爬虫框架有很多&#xff0c;比如Scrapy、BeautifulSoup等。本文选择使用Scrapy框架&#xff0c;因为它具有强…

用python测试网络上可达的网络设备

用python测试网络上可达的网络设备 之前使用的os在python中执行ping测试网络中可达的目标&#xff0c;但是他在执行ping命令时脚本会将系统执行ping时的回显内容显示出来&#xff0c;有时这些回显并不是必要的。如果用脚本一次性ping成百上千台网络设备或者URL时会影响美观和阅…

电商API接口开发和接入说明{包含淘宝/京东/拼多多/抖音}

“为什么改了这个没告诉我” “实际功能和文档上说的不一样啊”。 这些话大家在进行电商API接口开发时&#xff0c;想必耳朵都听出老茧了。 真不是故意的&#xff0c;有时候任务比较急&#xff0c;就先改了代码&#xff0c;想着以后再同步文档&#xff0c;然后就给忘了。 项…

【Vue】vue | npm run build打包缺少模块 | 打包缺少模块代码

一、说明 1、项目时间长了&#xff0c;vue的node_modules依赖竟然到了16个G 2、之前npm run build:prod都是可以的 3、最新一次竟然失败了&#xff0c;说缺少模块 二、解决 1、删除node_modules模块 2、强删缓存 npm cache clear --force 3、删除package-lock.json 4、重新…

【C++】:set和map

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

HomeAssistant如何添加HACS插件实现公网控制米家与HomeKit等智能家居

HomeAssistant添加HACS插件并实现公网控制米家&#xff0c;HomeKit等智能家居 文章目录 HomeAssistant添加HACS插件并实现公网控制米家&#xff0c;HomeKit等智能家居基本条件一、下载HACS源码二、添加HACS集成三、绑定米家设备 ​ 上文介绍了如何实现群晖Docker部署HomeAssist…

不是Typescript用不起,而是JSDoc更有性价比?

1. TS不香了&#xff1f; 2023年&#xff0c;几条关于 Typescript 的新闻打破了沉寂&#xff0c;让没什么新活好整的前端开发圈子又热闹了一番。 先是 GitHub 的报告称&#xff1a;“TypeScript 取代 Java 成为第三受欢迎语言”。 在其当年度 Octoverse 开源状态报告中&#x…

如何通过navicat连接SQL Server数据库

本文介绍如何通过Navicat 连接SQL Server数据库。如果想了解如何连接Oracle数据库&#xff0c;可以参考下边这篇文章。如何通过Navicat连接Oracle数据库https://sgknight.blog.csdn.net/article/details/132064235 1、新建SQL Server连接配置 打开Navicat软件&#xff0c;点击…