JVM的组成、字节码文件的组成
目录
java虚拟机的组成
字节码文件的组成
基础信息
常量池
字段
方法
属性
字节码相关的常用工具:
总结:
1、如何查看字节码文件?
2、字节码文件的核心组成有哪些?
java虚拟机的组成
- 类加载器 ClassLoader
- 运行时数据区域(JVM管理的内存)
- 执行引擎(即时编译器、解释器 垃圾回收器等)
- 本地接口
字节码文件的组成
使用Jclasslib进行查看
- 基础信息
- 常量池
- 字段
- 方法
- 属性
基础信息
魔数,字节码文件对应的java版本号访问标识(public final等等)父类和接口
魔数:
- 文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改,不影响文件的内容。
- 软件使用文件的头几个字节(文件头)去效验文件的类型,如果软件不支持该种类型就会出错。
- Java字节码文件中,将文件头称为magic魔数:cafebabe
主副版本号:
- 主副版本号指的是编译字节码文件的JDK版本号 (副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号)
- 版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容
- 下面的这个例子解释版本为6的java运行了java8中的内容了
解决方案:
1、升级JDK版本
2、将第三方以来的版本号降低或者更换依赖,以满足JDK版本的要求
我们一般会采用第二种方式,因为在项目中JDK的版本的更换可能会产生更多的版本冲突问题。
常量池
保存了字符串常量、类或接口名、字段名主要在字节码指令中使用
- 字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。
- 常量池中的数据都有一个编号,编号从1开始。在字段或者字节码指令中通过编号可以快速找到对应的数据。
- 字节码指令中通过编号引用到常量池的过程称之为 符号引用
字段
当前类或者接口声名的字段信息
方法
当前类或接口声名的方法信息字节码指令
案例1:
j的最终结果是1
案例2:
i的最终结果是0
案例3:
i的最终结果是1
i++ 和 ++i 在字节码的流程解读中的具体的操作顺序是有变化的
指令解读:
iconst_0 | 向操作数栈中添加0 |
istore_1 | 将操作数栈中的数出栈放在局部变量表数组下标为1的地方 |
iload_1 | 将局部变量表中下标为1的数据复制一份到操作数栈中 |
iinc 1 by 1 | 将局部变量表中的数据进行自增操作 |
案例2
回答:答案是0,我通过分析字节码指令发现,i++先把0取出来放入临时的操作数栈中,接下来对i进行+1,i变成了1,最后再将之前保存的临时之0放入i,最后i就变成了0。
属性
类的属性、比如源码的文件名 内部类列表等
字节码相关的常用工具:
javap 、jclasslib插件、阿里arthas,使用工具查看字节码文件中的详细信息
阿里arthas:宝藏工具 (阿尔萨斯)
监控线上运行中的系统,并且能够发现其中的一些问题,同时又能够帮助我们去解决这个问题的一款工具
- 监控面板
- 查看字节码信息
- 方法监控
- 类的热部署
- 内存监控
- 垃圾回收监控
- 应用热点定位
dashboard:打印所检测执行文件的相关信息
dump:将class文件转存为字节码文件并放置在指定目录中。
jad:反编译已加载类的源码。
curl :提供访问的拼接条件,对接口进行访问
案例:使用阿里arthas定位线上出现的字节码问题
背景:不知道知否将最新的字节码文件部署到服务器上,请使用阿里的arthas去确认升级完的字节码文件是不是最新的。
思路:
- 在出问题的服务器上部署一个arthas,并启动
- 连接arthas的控制器,使用jad命令加上想要查看的类名,反编译出源码。
- 确认源码是否是最新的。
总结:
1、如何查看字节码文件?
- 如果是本地的文件,可以直接使用jclasslib开打进行查看,开发环境的话 可以使用jclasslib插件
- 如果是在服务器上文件使用javap命令直接查看,也可以通过arthas的dump命令导出字节码文件再查看本地的文件。还可以使用jad命令反编译出源代码。
2、字节码文件的核心组成有哪些?
- 基本信息:魔数、字节码文件对应的java版本号访问标识(public final等等)
- 常量池:保存了字符串常量、类或者接口名、字段名主要在字节码指令中使用
- 字段:当前类或者接口声名的字段信息
- 方法:当前类或者接口声名的方法信息字节码指令
- 属性:类的属性,比如源码的文件名,内部类的列表等等