Java bytecode 玩法不完全指北
2020-03-05
Abstract:打开
.class
文件康康 byte code
的组成 & 字节码增强是什么(以Jvms8为例)
要玩bytecode,还是先简单看一眼bytecode的设计定位和内部结构
What ?
-
bytecode是一套Java虚拟机的指令集,或者说是以.class文件为形式的机器码,再通过Java interpreter对接各种不同的操作系统,以此帮助Java实现了平台独立性,也就是compile once,run every where
-
另外,由于只要满足字节码的形式,JVM甚至可以兼容其他语言(Kotlin、Scala),大大提高了扩展性,当然本篇还是以Java为例
How ?
- .java 通过 javac 编译生成 .class文件
- .class文件通过 Java interpreter对接操作系统和硬件(当然不包括native method)
Structure
- 上表中的结构不局限于HotSpot虚拟机,而是JVM Specification中的规定
- 下面以这样一个自定义类为例:
/**
* @author GabbyYam
* @date 2020/3/5
*/
public class YamCode {
public String yam_name;
private int yam_total;
public String getYam_name() {
return yam_name;
}
public void setYam_name(String yam_name) {
this.yam_name = yam_name;
}
public int getYam_total() {
return yam_total;
}
public void setYam_total(int yam_total) {
this.yam_total = yam_total;
}
}
magic
- 对其
javac
编译:可见.class文件中存在magic标记:cafebabe,代表初代开发团队成员喜欢的一种咖啡,是class文件的标记符
- 为了方便理解(字节码也没法理解),我们
javap -verbose
反编译,将其转换为可理解的代码
- 全限定类名、版本号以及权限控制相关的标记符
版本号
- 主次版本号从45起记,各版本号范围依次为
- 新版本可以兼容低版本,反之则不行
访问控制符
- 其中MODULE为Java9新增的部分
常量池 Constant pool
- 需要注意的是常量池中的常量具备动态性,也就是说,不一定在编译期产生,比如常见的String.intern(String.valueOf(“xx”))
- 也是基于动态性,常量池需要向
Method Area
申请方法区内存,所以有OutOfMemoryError的可能
方法属性method_info
其中有三段重要信息
Code:即方法内包含的操作码集合
- 对应JVM指令操作码,比如图中的aload_0表示将局部变量压入操作数栈,详细操作码解释参见Java bytecode instruction listings
LineNumberTable
-
Code中操作码对应源码的行数,也即下面这句话对应的位置
return yam_name;
LocalVariableTable
- 方法内局部变量表