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

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

文章目录

  • 一、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_01 istore_12 iinc 1 by 15 iload_16 istore_17 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.mzph.cn/news/121701.shtml

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

相关文章

进程间通信(匿名管道、命名管道、消息队列、共享内存、信号量、信号、Socket)

文章目录 一、什么是进程间通信二、管道1.匿名管道(pipe)a).创建匿名管道b).管道的读写规则c).匿名管道的特点 2.有名管道(FIFO)a).创建命名管道b).命名管道的特点c).基于命名管道的进程间通信&#xff08;服务端/客户端&#xff09; 三、消息队列四、共享内存1.什么是共享内存…

react高阶成分(HOC)例子效果

使用React函数式组件写了一个身份验证的一个功能&#xff0c;示例通过高阶组件实现的一个效果展示&#xff1a; import React, { useState, useEffect } from react;// 定义一个高阶组件&#xff0c;它接受一个组件作为输入&#xff0c;并返回一个新的包装组件 const withAuth…

(C++进阶)正则表达式

目录 一、概念 1、简介 2、字符规则 二、常用函数 1、std::regex_match 2、std::regex_search 3、std::regex_replace 三、std::smatch 一、概念 1、简介 正则表达式&#xff08;Regular Expression&#xff09;&#xff0c;通常简写为RegExp或Regex&#xff0c;是一种…

装了mac os 14.0 sonoma 在腾讯会议投屏时候,无法设置麦克风权限问题

愿意&#xff1a;界面上直接空白的&#xff0c;无法手动或自动弹出要配置授权的软件 解决思路&#xff1a; 给 TCC.db 增加1条权限记录 添加到数据库里 /usr/bin/sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT INTO main.access (service, cli…

windows PC virtualBox 配置

效果&#xff1a; oracle vitualbox 可以访问通PC主机&#xff0c;可以访问外网: 注意&#xff0c;如果docker0网络地址&#xff0c;和PC主机的网络地址冲突了&#xff0c;需要变更docker的网络地址&#xff1a; root/home/mysqlPcap/anti-tamper $ cat /etc/docker/daemon.js…

YOLOv5算法改进(21)— 添加CA注意力机制 + 更换Neck网络之BiFPN + 更换损失函数之EIoU

前言:Hello大家好,我是小哥谈。通过上节课的学习,相信同学们一定了解了组合改进的核心。本节课开始,就让我们结合论文来对YOLOv5进行组合改进(添加CA注意力机制+更换Neck网络之BiFPN+更换损失函数之EIoU),希望同学们学完本节课可以有所启迪,并且后期可以自行进行YOLOv5…

GPT与创作:革命性的合作还是失业的噩梦?

作为一个从事互联网行业的从业者&#xff0c;我经常听到关于GPT的争议性言论。百度的​1​、CSDN的​2​&#xff0c;以及各种AI助手&#xff0c;这些工具在创作领域掀起了一场革命。但是&#xff0c;人们担心广泛使用GPT是否会导致人们失业&#xff0c;甚至挑战互联网公司的存…

【MySQL数据库重点】第二节:MySQL基础知识(基本操作)

目录 一&#xff1a;数据库的操作 1.显示数据库 2.创建数据库 3.使用数据库 4.删除数据库 二&#xff1a;常用数据类型 1.数值类型&#xff1a;整型和浮点型 2.字符串类型 3.日期类型 三&#xff1a;表的操作 1.查看表结构 2.创建表 3.删除表 一&#xff1a;数据库…

wait和sleep是否会触发锁的释放以及 CPU 资源的释放?

wait和sleep Object.wait()方法&#xff0c;会释放锁资源以及 CPU 资源。 Thread.sleep()方法&#xff0c;不会释放锁资源&#xff0c;但是会释放 CPU 资源。 wait 方法 wait()方法是让一个线程进入到阻塞状态&#xff0c;而这个方法必须要写在一个Synchronized 同步代码块里面…

Dubbo 路由及负载均衡性能优化

作者&#xff1a;vivo 互联网中间件团队- Wang Xiaochuang 本文主要介绍在vivo内部针对Dubbo路由模块及负载均衡的一些优化手段&#xff0c;主要是异步化缓存&#xff0c;可减少在RPC调用过程中路由及负载均衡的CPU消耗&#xff0c;极大提升调用效率。 一、概要 vivo内部Java…

工厂干洗店洗鞋店系统,校园洗护小程序来了

洗鞋店小程序&#xff0c;干洗店软件&#xff0c;洗护行业小程序,上门取衣小程序,预约干洗小程序,校园干洗店小程序,工厂干洗店小程序,干洗店小程序开发&#xff0c;成品软件开发 洗衣工厂软件、功能强大&#xff01; 包含以下主要功能&#xff1a; * 用户选择洗护用品&#x…

OS的Alarm定时器调度机制

调度表触发的任务在编译时就被静态定义&#xff0c;任务的触发时间和执行顺序是固定的。这种方式适用于已知的、固定的任务触发模式&#xff0c;例如周期性任务或事件驱动任务。而使用 Alarm 机制触发的任务具有更大的灵活性。Alarm 允许在运行时动态地设置和修改任务的触发时间…

计算机网络--第一次作业

1、比较电路交换、报文交换和分组报文交换优缺点 电路交换 电路交换是以电路连接为目的的交换方式&#xff0c;通信之前要在通信双方之间建立一条被双方独占的物理通道&#xff08;由通信双方之间的交换设备和链路逐段连接而成&#xff09;。 优点&#xff1a; ①由于通信线路为…

薛定谔的猫重出江湖?法国初创公司AliceBob研发猫态量子比特

总部位于巴黎的初创公司Alice&Bob使用超导芯片的两个相反的量子态&#xff08;他们称之为“猫态量子比特”芯片&#xff09;来帮助开发量子计算的不同自旋方式。&#xff08;图片来源&#xff1a;网络&#xff09; 有的人认为&#xff0c;构建量子计算机的模块模仿了著名的…

链动2+1全新9.0版本 无限链动收益

一个平台能否长期存活取决于它是否有一个支撑其持续发展的商业模式。蜂群精选深谙用户心理&#xff0c;对链动21模式进行改造&#xff0c;创新出一种同时具备裂变能力和高效吸引用户留存的新玩法。 链动21模式在整个架构上都是完整的&#xff0c;可以说是一个非常出色的营销模式…

ruoyi-plus创建模块、自动生成代码

ruoyi-plus自动生成代码 1、创建模块 复制其他部分的resouce过来 修改yml文件 2 修改Nacos 2.1 修改数据库文件 复制其他数据库的链接 &#xff0c;改为自己新建的数据库名字 修改为自己要生成的数据库 新建数据库的yaml文件 3 重启docker的ruoyi-gen服务 docker re…

新手向:如何考虑将数据库技术和大数据框架结合使用?

结合的意义/应用场景与功能分摊 结合场景 大规模数据处理&#xff1a;当数据量巨大&#xff0c;超出传统数据库的处理能力时&#xff0c;大数据框架可以高效地处理这些数据&#xff0c;而传统数据库可以为应用程序提供实时或交互式查询。 混合工作负载&#xff1a;企业通常需…

ClickHouse快速了解

简介 ClickHouse是一个开源列式数据库管理系统&#xff08;DBMS&#xff09;&#xff0c;用于在线分析处理&#xff08;OLAP&#xff09;&#xff1a; 列式存储&#xff1a;与传统的行式数据库不同&#xff0c;ClickHouse以列的形式存储数据&#xff0c;这使得在分析大量数据时…

敏感词过滤--golang

目录 1. 建立敏感词数据库表2. 定时任务&#xff0c;读数据并建立敏感词树2.1 开启定时任务2.2 读数据并建立敏感词树 3. 使用 思路&#xff1a; 将敏感词都存到数据库表中定时读取数据到内存中&#xff0c;构建敏感词前缀树写工具方法&#xff0c;使用内存中的前缀树判断消息…

docker - DockerFile 编写 指令

文章目录 前言docker - DockerFile 编写 指令1. FROM2. MAINTAINER3. RUN4. CMD5. LABEL6. EXPOSE7. ENV8. ADD9. COPY10. ENTRYPOINT11. VOLUME12. USER13. WORKDIR14. ARG15. ONBUILD16. STOPSIGNAL 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&am…