JVM基础:字节码文件详解①

news2024/11/24 4:37:14

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、Java虚拟机的组成
  • 二、字节码文件的组成
    • 2.1 为什么要了解字节码文件?
    • 2.2 如何“窥探”字节码文件的奥秘?
      • 2.2.1 使用工具打开字节码文件
      • 2.2.2 字节码文件是由哪几部分组成?
      • 2.2.3 基础信息(一般信息)
      • 2.2.4 常量池
      • 2.2.5 方法
  • 参考目录


提示:以下是本篇文章正文内容,下面案例可供参考

一、Java虚拟机的组成

👉它可以分为以下四个部分

  1. 类加载器(ClassLoder)加载class字节码文件中的内容到内存中(加载到内存是为了高效的利用)
  2. 运行时数据区域(JVM管理的内存)负责管理JVM使用到的内存,比如创建对象和销毁对象
  3. 执行引擎((即时编译器、解释器与垃圾回收器等)将字节码文件中的指令解
    释成机器码,同时使用即时编译器优化性能
  4. 本地接口调用本地已经编译的方法,比如虚拟机中提供的c/c++的方法,就是本地方法(即jvm底层已经实现好的,用C/C++语言编写好的方法,使用native修饰的方法)在这里插入图片描述

👉基本执行流程如下所示:

在这里插入图片描述


二、字节码文件的组成

2.1 为什么要了解字节码文件?

👉原因

①它可以解决一些面试难题

例如以下面试题

  • int i = 0; i = i++; 最终i的值是多少?
  • 请你回答一下Java的反射是如何实现的?

②它可以解决工作中的一些实际问题——版本冲突

例如以下报错

在这里插入图片描述

2.2 如何“窥探”字节码文件的奥秘?

2.2.1 使用工具打开字节码文件

👉常用工具

①使用Jclasslib字节码插件【idea插件】

在这里插入图片描述

如何使用该插件查看指定字节码文件?

👉步骤

①在idea中 file – settings – plugins 中搜索 jclass 安装该插件

在这里插入图片描述
②选中指定的Java源文件,按照以下步骤操作,即可
在这里插入图片描述
在这里插入图片描述

👉注意

使用jclasslib的idea插件版的两个小细节

  1. 要打开一个新的字节码文件,就需要选中当前的源代码,然后点击 view - show bytecode with jclasslib 就可以打开新的字节码文件

    在这里插入图片描述

    1. 如果源代码发生变化,需要重新运行编译,可通过 build - Recompile ‘xxx.java’ 或 重新运行该源代码的方式重新编译,然后在jclasslib中重新刷新即可
      在这里插入图片描述

②使用Javap命令

如何使用该命令查看指定字节码文件?

👉步骤

  1. 首先确保已经安装了JDK(Java Development Kit),因为Javap是JDK的一部分。

  2. 打开命令提示符(Windows)或终端(macOS/Linux)。

  3. 使用cd命令导航到包含字节码文件(.class文件)的目录。例如,如果字节码文件位于C:\Users\YourUsername\Documents\MyProject目录下,请输入cd C:\Users\YourUsername\Documents\MyProject

  4. 输入javap -c YourClassName.class命令,其中YourClassName是你要查看的字节码文件的名称(不包括扩展名)。例如,如果你要查看名为MyClass.class的文件,请输入javap -c MyClass.class

  5. 按回车键执行命令。命令将显示字节码文件的详细信息,包括类名、方法名、参数类型等。

案例:使用Javap命令打开桌面测试文件夹中的字节码文件t1.class

在这里插入图片描述

👉备注

如果jar包需要先使用 jar –xvf 命令解压

③使用Arthas工具打开字节码文件

GitHub地址

在这里插入图片描述

2.2.2 字节码文件是由哪几部分组成?

使用jclass插件打开任意一个Java 源文件,我们可以看到如下信息

在这里插入图片描述

  • 一般信息(基本信息)魔数、字节码文件对应的Java版本号,访问标识(public final等等)以及父类和接口

    在这里插入图片描述

  • 常量池保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用

    在这里插入图片描述

  • 接口当前类实现的接口信息

    在这里插入图片描述

  • 字段当前类或接口声明的字段信息

    在这里插入图片描述

  • 方法当前类或接口声明的方法信息——字节码指令

    在这里插入图片描述

  • 属性类的属性,比如源码的文件名,内部类的列表等

    在这里插入图片描述

2.2.3 基础信息(一般信息)

在这里插入图片描述

前面提到的基本信息中主要包含魔数、字节码文件对应的Java版本号,访问标识(public final等等)以及父类和接口等内容,但是有两个问题值得深思

在这里插入图片描述

😥问题①:何为魔数?

使用notepad++ 随便打开两个字节码文件,我们可以看到他们之间显著的共通之处

a.打开t1.class字节码文件,如下图所示

在这里插入图片描述

b.打开MyApplication.class字节码,如下图所示

在这里插入图片描述

共通之处

以ca fe ba be打头

这就是魔数(Magic),用以校验文件类型的文件头,如果别的编译软件不支持该种类型的文件头,则解析文件时会出错。那为什么不使用文件扩展名去校验类型?文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改,不影响文件的内容。故而在Java字节码文件中,将文件头称为魔数

在这里插入图片描述

😥问题②:何为Java版本号?

Java版本号主要分为主副版本号,主副版本号指的是编译字节码文件的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。

在这里插入图片描述

👉版本号作用

主要判断当前字节码的版本和运行时的JDK是否兼容

👉备注

1.2之后大版本号计算方法就是:主版本号 – 44 ;
比如主版本号52,那就是JDK8

之前在前文中抛出了一个版本冲突的问题

如下图所示

在这里插入图片描述

👉原因

主版本号不兼容,发生冲突

👉解决方案

1.升级JDK版本(容易引发其他的兼容性问题,并且需要大量的测试)
2.将第三方依赖的版本号降低或者更换依赖,以满足JDK版本的要求 √ 建议采用

👉总结

在这里插入图片描述

2.2.4 常量池

👉作用

避免相同的内容重复定义,节省空间

👉概述

  • 常量池中的数据都有一个编号,编号从1开始。在字段或者字节码指令中通过编号可以快速的找到对应的数据
  • 字节码指令中通过编号引用到常量池的过程称之为符号引用

👉符号引用的示意图如下所示

在这里插入图片描述

2.2.5 方法

👉先看一个简单经典的面试题

int i = 0; i = i++; 最终i的值是多少?

👉我的回答

i =i++ 是先赋值后自增,而i= ++ i 是先自增后赋值,所以最终的i是0

😚进一步发问

为什么i =i++ 是先赋值后自增,而i= ++ i 是先自增后赋值,如果根据Java的运算符优先级对比,应该是1吧,i++优先级高,先执行之后将返回结果1赋值给 i,所以最终 i应该是1。

可正确的答案是 i最终的值是0

😥why?

莫急,且听我慢慢道来

👉定义

字节码中的方法区域是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中

在这里插入图片描述

选中Code属性,我们可以看到它下面还有两个Table

在这里插入图片描述

  • LineNumberTable用于存储源代码中各行号与字节码指令之间的对应关系,它可以帮助调试器在执行程序时定位到源代码中的具体位置。

    在这里插入图片描述

  • LocalVariableTable主要用于存储方法的参数和方法内定义的局部变量。在程序编译为Class文件时,会在Code属性的max_locals数据项中确定该方法所需要分配的局部变量表的最大容量。

    在这里插入图片描述

我们暂时只关心LocalVariableTable,如下图所示,LocalVariableTable表中的每个项都包含以下内容:

  • 名称(Name)表示该项对应的局部变量的名称
  • 描述符(Descriptor)表示该项对应的局部变量的类型和修饰符
  • 索引(Slot)表示该项在局部变量表中的位置
  • 值(Value)表示该项对应的局部变量的值

在这里插入图片描述

除了上面的LocalVariableTable,我们还得了解一个概念——操作数栈

😥什么是操作数栈?

👉讯飞星火告诉我们

在这里插入图片描述

简单来讲,操作数栈是临时存放数据的地方

👉再看之前的源代码

 int i=0;
 int j= i+1;

字节码指令分析如下

在这里插入图片描述
回到前面提到的面试题

😥为什么int i = 0; i = i++; 最终i的值是0?

源代码示例如下

public static void main(String[] args) {
        int i=0;
        i=i++;
        System.out.println("i = " + i);
}

在这里插入图片描述

👉分析流程如下所示

在这里插入图片描述
👉举例分析

以 int i=0; i=++i; 的字节码指令展开分析,最后i的值是多少?

示例代码如下

 public static void main(String[] args) {
        int i=0;
        i=++i;
        System.out.println("i = " + i);
 }

字节码指令如下

 0 iconst_0
 1 istore_1
 2 iinc 1 by 1
 5 iload_1
 6 istore_1
 7 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
10 new #3 <java/lang/StringBuilder>
13 dup
14 invokespecial #4 <java/lang/StringBuilder.<init> : ()V>
17 ldc #5 <i = >
19 invokevirtual #6 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
22 iload_1
23 invokevirtual #7 <java/lang/StringBuilder.append : (I)Ljava/lang/StringBuilder;>
26 invokevirtual #8 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
29 invokevirtual #9 <java/io/PrintStream.println : (Ljava/lang/String;)V>
32 return

👉流程分析如下

①将int类型的 o push 操作数栈中;
②从操作数栈中取出0,放入到局部变量表中位序为1的位置上[i],此时i=0;
③在局部变量表中为位序为1的位置上增加1,此时i=1;
④从局部变量表中位序为1的位置将数据压入到操作数栈中,此时i=0;
⑤将操作数栈中的数据[1]保存到局部变量表中位序为1的位置上,此时i=1;

👉备注

如果不清楚某一条指令的作用,可采取以下步骤

①选中指令,点击“显示JVM规范”

在这里插入图片描述
②浏览器会自动跳转至对应指令的详情页面

在这里插入图片描述


参考目录

https://www.bilibili.com/video/BV1r94y1b7eS?p=7&spm_id_from=pageDriver&vd_source=5a34715e416a427a73a3ca52397848b5


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

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

相关文章

09循环嵌套

循环嵌套顾名思义循环里面套循环 # 循环嵌套顾名思义循环里面套循环a 1 b 0 while a < 10:# print(1, a)b 1while b < a and b < 10:print("%d*%d%d" % (b, a, a * b), end" ")b 1print()a 1format 格式化运算符 只需要填入数据即可 print(…

Mathtype使用指南01:下载与安装

目录 介绍&#xff1a; 安装 介绍&#xff1a; MathType 是一款广泛用于数学和科学文档创建的强大数学编辑工具。它允许用户轻松地在各种文档类型中插入数学方程、符号和公式&#xff0c;是学术界、工程领域、出版界和教育机构中的专业人士常用的工具。下面是关于 MathType 的…

ChineseChess6 2023.10.28

中国象棋残局&#xff1a;黑一卒一车 这红棋好像也是无解哦

如何使用ffmpeg制作透明背景的视频

最近我们尝试在网页上叠加数字人讲解的功能&#xff0c;发现如果直接在网页上放一个矩形的数字人视频&#xff0c;效果会很差&#xff0c;首先是会遮挡很多画面的内容&#xff0c;其次就是不管使用任何任务背景&#xff0c;画面都和后面的网页不是很协调&#xff0c;如图所示&a…

2-多媒体数据压缩国际标准

文章目录 多媒体数据压缩编码的重要性和分类为什么要压缩?计算: 未压缩音频的数据率简答: 环绕声系统-作业题9(简述7.4.3全景声)计算: 未压缩图像的数据量-作业题10(估计尺寸及容量)计算: 未压缩视频的数据率 为什么能压缩?数据压缩编码的两大类无损压缩算法: LZ77-作业题6-(…

Visual Studio Code的下载与安装

Visual Studio Code&#xff08;简称 VS Code&#xff09;是由 Microsoft 开发的免费、开源的文本编辑器&#xff0c;适用于多种操作系统&#xff0c;包括 Windows、macOS 和 Linux。它的设计目标是成为一款轻量级、高效的代码编辑工具&#xff0c;同时提供丰富的扩展和功能&am…

计算机毕业设计 基于SpringBoot大学生就业服务平台的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

【数据结构】交换排序

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 冒泡、快速排序 1. 冒泡排序2. 快速…

Android应用:实现网络加载商品数据【OKHttp、Glide、Gson】

实现网络加载商品数据的功能&#xff1a; 1、在AndroidManifest.xml中声明网络权限&#xff1b; 2、在app/build.gradle中添加okhttp, glide, gson等必需的第3方库&#xff1b; 3、在MainActivity中通过OkHttpClient连接给定的Web服务&#xff0c;获取商品数据&#xff1b;对…

Android笔记(九):Compose组件的状态(一)

在使用Compose定义UI界面时&#xff0c;可以发现界面的变换往往与Compose组件内部的状态相关&#xff0c;当状态值发生变化时&#xff0c;Compose构成的可组合的界面也会刷新发生相应的变化。将在本笔记中将对可组合项的状态的定义、状态提升、状态丢失和状态的保存进行简单介绍…

Linux(Centos)防火墙允许通过端口增加操作记录

1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误&#xff0c;并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…

Spring Boot进阶(93):体验式教程:手把手教你整合Spring Boot和Zipkin

&#x1f4e3;前言 分布式系统开发中&#xff0c;服务治理是一个比较重要的问题。为了更好地实现服务治理&#xff0c;需要解决服务跟踪问题&#xff0c;即如何对分布式系统中的服务进行监控和追踪。本文将介绍如何使用Zipkin进行服务跟踪&#xff0c;并结合Spring Boot进行整合…

【操作系统】文件管理大题总结

【操作系统】文件管理大题总结 文章目录 【操作系统】文件管理大题总结前置知识操作系统中的存储单位转换 1、目录管理中的典型问题分析基础例题&#xff1a;往年真题 2、外存的组织方式中的典型问题分析基础例题王道课后题往年真题 3、文件存储空问管理中的典型问题分析基础例…

Linux ln命令:建立链接文件

如果要想说清楚 ln 命令&#xff0c;则必须先解释下 ext 文件系统&#xff08;Linux 文件系统&#xff09;是如何工作的。我们在前面讲解了分区的格式化就是写入文件系统&#xff0c;而我们的 Linux 目前使用的是 ext4 文件系统。如果用一张示意图来描述 ext4 文件系统。 ext4 …

Django之登录注册

最近在准备上线一个网站&#xff08;基于django的编程技术学习与外包服务网站&#xff09;&#xff0c;所以会将自己的在做这个项目的过程中遇到的模块业务以及所涉及到的部分技术记录在CSDN平台里&#xff0c;一是希望可以帮到有需要的同学&#xff0c;二十以供自己后续回顾学…

Jmeter调用Python脚本实现参数互相传递的实现

这篇文章主要介绍了Jmeter调用Python脚本实现参数互相传递的实现&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧 接口性能测试时&#xff0c;接口请求参数是根据一…

蓝桥杯每日一题2023.10.28

题目描述 递增三元组 - 蓝桥云课 (lanqiao.cn) 题目分析 60分解法&#xff1a; 直接暴力循环每一个数进行比较 #include<bits/stdc.h> using namespace std; const int N 2e5 10; typedef long long ll; ll n, a[N], b[N], c[N], ans; int main() {cin >> n;…

C++STL---Vector、List所要掌握的基本知识

绪论​ 拼着一切代价&#xff0c;奔你的前程。 ——巴尔扎克&#xff1b;本章主要围绕vector和list的使用&#xff0c;以及容器底层迭代器失效问题&#xff0c;同时会有对原码的分析和模拟实现其底层类函数。​​​​话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑…

shouldComponentUpdate 是做什么的?

目录 前言 生命周期函数 shouldComponentUpdate 的写法和用法 代码 事件和API 优缺点 方法 总结 理论 结论 shouldComponentUpdate 是 React 类组件中的一个生命周期方法&#xff0c;用于决定一个组件的 props 或 state 发生变化时是否应该重新渲染。默认情况下&…

HBuilderX 自定义语法提示

在开发实践中&#xff0c;会使用到各种第三方组件&#xff0c;比如Element UI&#xff0c;通常的做法是到官网中复制模板再在本地根据设计要求进行修改&#xff0c;或是从其它已经实现的组件中复制相似的内容。但每次复制粘贴确实比较麻烦。 在HBuilderx中可以设置代码块来创建…