JVM-03-字节码文件

文章目录

  • [0. 什么是字节码文件](#0. 什么是字节码文件)
  • [1. 打开字节码文件](#1. 打开字节码文件)
  • [2. 字节码文件的组成](#2. 字节码文件的组成)
    • [2.1 一般信息 ⭐](#2.1 一般信息 ⭐)
    • [2.2 常量池 ⭐](#2.2 常量池 ⭐)
    • [2.3 方法 ⭐](#2.3 方法 ⭐)
  • [3. 字节码常用工具](#3. 字节码常用工具)
    • [3.1 javap](#3.1 javap)
    • [3.2 jclasslib插件](#3.2 jclasslib插件)
    • [3.3 阿里Arthas](#3.3 阿里Arthas)
      • 常用命令
        • [① dashboard](#① dashboard)
        • [② dump](#② dump)
        • [③ jad](#③ jad)
  • 总结

0. 什么是字节码文件

字节码文件是一种介于源代码和机器码之间的二进制中间代码文件,用于在虚拟机上执行程序。

jvm不关心运行在内部的是什么语言编写的,只关心字节码

要想使得Java文件在jvm中正确运行,就需要转为字节码文件。

类比理解

1. 打开字节码文件

使用Notepad++的十六进制插件查看.class文件,先安装HEX Editor插件:

然后用插件打开.class文件。

插件 -> HEX Editor -> View in HEX

可以看到:

其中,左边表示当前文件中的地址,中间是十六进制数据,最后是编码后的结果。编译后的结果显示乱码,无法直观的查看到字节码文件。就需要使用工具来查看,比如jclasslib。

使用工具jclasslib(下载地址:https://github.com/ingokegel/jclasslib/releases),打开target目录下的`.class`文件,可以看到:

2. 字节码文件的组成

使用工具jclasslib打开target目录下的.class文件,可以看到:

  • 一般信息
  • 常量池
  • 接口
  • 字段
  • 方法
  • 属性

下方重点介绍一般信息、常量池、方法。

2.1 一般信息 ⭐

可以看到信息概览。

魔数 Magic ⭐

java字节码文件中,将文件头称为魔数 Magic。class文件开头4个字节固定为cafebabe。

  • 作用:jvm可以通过文件头可以判断是否是一个合法的class文件。因为文件的扩展名是可以修改的,比如png可以改成avi,通过文件头可以看到原始文件类型。

    因此,我们通过软件去打开文件时,软件会校验文件头来获取类型,如果不支持,就会报错。

其他的文件类型对应的文件头:

主次版本号

指class由哪个版本Java编译。主版本号用来标识大版本号,jdk1.2之后每升级一个大版本就+1。主版本号减去44就是jdk的版本号,比如61-44=17,jdk就是17。

2.2 常量池 ⭐

  • 作用:避免相同内容,重复定义,节省空间。
  • 常量池中的数据都有一个编号,从1开始。通过编号可以快速找到对应的数据。

2.3 方法 ⭐

存储该方法的所有元数据定义,以及供 Java 虚拟机(JVM)实际执行的指令序列(运行逻辑)。

以下方代码为例:

java 复制代码
public void test07(){
    int i = 0;
    i = i++;
    System.out.println(i);
}

用jclasslib打开对应的字节码文件:

通过右击指令名,可以显示JVM规范,也就是该指令在jvm中的含义。

其中,

  • iconst_<i>表示:将int常量i放到操作数栈中。iconst_0也就表示将常量0放到操作数栈中。
  • istore_<n>表示:操作数栈出栈,在局部变量表的索引为n的地方设置该值。那么istore_1表示,将前一步入栈的常量0出栈,放到局部变量表下表为1的地方。
  • iload_<n>表示:将局部变量表中下标为n的值入栈操作数栈。那么iload_1则表示将常量表中下标为1的值也就是0,放到操作数栈。(注意:入栈不影响常量表中的值)
  • iinc表示:将局部变量表中索引下标中的值增加。那么iinc 1 by 1表示将常量表下标为1的值增加1。

    那么,整个字节码可以解释为:
    0 将常量0放到操作数栈中。stacktop=0
    1 将常量0出栈,放到局部变量表下表为1的地方。local1=0
    2 将常量表中下标为1的值,放到操作数栈。stacktop=0
    3 将常量表下标为1的值增加1。local1=1
    6 将常量0出栈,放到局部变量表下表为1的地方。local1=0
    10 将常量表中下标为1的值,放到操作数栈。stacktop=0

注意:局部变量表不能直接运算,必须放到操作数栈中。

综上,常量表下标为1的值为0,也就是说i的值为0。

3. 字节码常用工具

3.1 javap

是JDK自带的反编译工具,可以通过控制台查看字节码文件的内容。适合在服务器上查看字节码文件内容。

  • 检查javap命令是否可用:

    一般安装了java环境就会有

  • 这里以为jar包为例,先使用命令jar -xvf xx.jar将jar包解压:

  • 解压后字节码文件全部存放在BOOT-INF中。

  • 查看某个字节码文件的信息,并保存在.txt文件:javap -v 地址\xx.class > 地址\xx.txt

    得到包含所有完整字节码内容的文件

3.2 jclasslib插件

idea中有jclasslib插件,可以通过该插件在代码编译后实时查看字节码内容。

View->Show Bytecode With Jclasslib 可以查看到对应的字节码文件。(注意一定要先选中要查看字节码文件的源代码,否则不会出现这个选项)

右侧可以看到对应的字节码文件信息

注意:如果源代码内容发生改变后,需要先编译才能看到最新的字节码文件。

点击刷新

以上两款工具都是针对本地或者服务器上静态查看字节码文件,如果程序在运行了要怎么查看类的字节码信息?

3.3 阿里Arthas

Arthas是阿里巴巴开源的 Java 在线诊断工具,主要用于生产环境排查 Java 应用问题,能够实时查看应用load、内存、gc、线程的状态信息。

下载:https://arthas.aliyun.com

官方文档:https://arthas.aliyun.com/doc

  • 下载安装包:
  • 解压:
  • 启动arthas:
    可以看到所有在运行中的程序
  • 查看指定程序,输入编号,这里输入1为例:

常用命令

① dashboard

查看 JVM 总览:

这里执行dashboard -i 2000 -n 1,即每2秒刷新一次,刷新次数为一次,可以看到如下效果:

可以看到程序状态、CPU占有率、内存占用、GC、操作系统、java版本、CPU核数等等

② dump

把 JVM 中已经加载的某个类的字节码文件导出到本地磁盘。

执行命令:dump -d "D:\test\jvm\data" com.example.utils.UtilsApplication

可以查看到生成的字节码文件

③ jad

将运行中的类的字节码信息反编译为源码。通过该命令可以确认源代码是不是最新的。

通过jad 类名命令拿到源代码,这里以jad com.example.utils.UtilsApplication为例:

总结

  1. 打开字节码文件方式:jclasslib、javap命令、idea插件、arthas
  2. 其中arthas可以用于查看运行时的类的字节码信息,可以通过jad命令拿到反编译的源码,可以用于处理线上问题。

以上为个人学习分享,如有问题,欢迎指出:)

相关推荐
wuminyu1 小时前
JUC包的AQS与JVM的ObjectMonitor机制对比分析
java·linux·c语言·jvm·c++
梦云莓铃 脚后跟法14 小时前
从一个真实案例理解 JVM 标量替换
jvm
看浪的路人15 小时前
第3讲:手写第一个 MCP Server(Python SDK)
jvm·数据库·oracle
lee_curry1 天前
RuoYi Cloud:Gateway、Auth、System 接入 Prometheus JVM 监控,并练习多副本、滚动升级和故障恢复
jvm·gateway·prometheus
CoderYanger1 天前
Java EE:9.JVM(课件内容-上篇)
java·jvm·程序人生·面试·职场和发展·java-ee·程序员创富
残月心殇 请珍惜枸1 天前
.NET陷阱之五:奇怪的OutOfMemoryException——大对象堆引起的问题与对策
java·jvm·.net
CoderYanger1 天前
Java EE:9.JVM(课件内容-下篇)
java·jvm·程序人生·面试·职场和发展·java-ee·学习方法
八角.。2 天前
方法参数与Debug按键
java·开发语言·jvm
Ming_studying3 天前
Python + SQLite FTS5 构建本地文档全文搜索器:增量索引、中文检索与高亮
jvm·数据库·python·sqlite