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命令拿到反编译的源码,可以用于处理线上问题。

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

相关推荐
用户094248568036 小时前
第9章:OpenJDK堆分代与 Serial/Parallel GC 基础
java·jvm
小陈不好吃9 小时前
深入理解 JVM 内存模型:从堆栈结构到 GC 日志分析实战
java·jvm·java-ee·jdk
liangbo714 小时前
12-JVM 调优方法论与参数速查
java·jvm
用户0942485680314 小时前
第8章:Java 内存模型(JMM)入门——可见性、有序性、原子性
java·jvm
西峰u16 小时前
Java多线程从入门到线程安全
java·开发语言·jvm
wuminyu1 天前
Kafka中sendfile与mmap实现机制解析
java·linux·c语言·jvm·c++
万年咸鱼1 天前
JVM 内存区域详解
jvm
Escalating_xu1 天前
【System V 信号量】从 P/V 原语到 Builder 封装:写出可控、可清理的进程互斥组件
java·linux·开发语言·jvm
HEJOO91 天前
JVM 参数调优实战指南
jvm
码农哈丁1 天前
从 JVM 到 Cargo:把整个 Kotlin 项目移植到 Rust 的踩坑实录
jvm·rust·kotlin