avatar

目录
Java-详解一个简单代码运行的汇编级操作

定义代码

  1. 详解一个简单而具体的操作
java
1
2
3
4
5
6
7
8
9
10
11
package MyTest;

public class Main {
int i = 9;

public static void main(String[] args) {
Main arg = new Main();
arg.i++;
System.out.println(arg.i);
}
}

分析汇编

<init>栈帧操作

Code
1
2
3
4
5
6
7
8
9
10
11
// 加载局部变量表的slot0号元素,初始化Main类,此时为半初始化状态。
0 aload_0
// 调用并初始化Main的父类即Object类,此时为半初始化状态
1 invokespecial #1 <java/lang/Object.<init>>
4 aload_0
// 因为9大于-128小于127,所以判定是字节常量,这一步的操作是把字节常量入栈。
5 bipush 9
// 给对象i进行赋值
7 putfield #2 <MyTest/Main.i>
// 返回
10 return

上述过程做的就是,半初始化一个Main类,并且完成最终的赋值操作,即完成初始化操作了。
所以这个过程在字节码中,称作<init>过程。值得注意的是,这只是针对运行main的主类在栈帧中才显示为init操作。如果中间new了一个其他类将不会开辟一个新的init栈帧,而是在方法栈帧的内部进行类初始化操作了。上述过程做的就是,半初始化一个Main类,并且完成最终的赋值操作,即完成初始化操作了。

栈帧所维护的局部变量表

Code
1
0	0	11	0	cp_info #15	cp_info #16

<init>对应的局部变量表,cp_info #15表示的是用String类型表示的thiscp_info #16表示Main这个类。


main栈帧操作

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 执行main方法体中的语句
// 首先创建一个空的Main类。
0 new #3<MyTest/Main>
// 复制栈顶数值,并压入栈顶
3 dup
// 实例化Main类,调用构造方法,半初始化状态。
4 invokespecial #4 <MyTest/Main.<init>>
// 将本地变量表的index为1的参数出栈。
7 astore_1
// 加载局部变量表的第一个参数,即arg。
8 aload_1
// 复制栈顶数值,并压入栈顶
9 dup
// 获取对象i字段的值
10 getfield #2 <MyTest/Main.i>
// 将常量1进栈
13 iconst_1
// 将Main.i的值和常量1进行相加
14 iadd
// 把结果在返回给对象的i字段
15 putfield #2 <MyTest/Main.i>
// 下面就是println的操作了
18 getstatic #5 <java/lang/System.out>
21 aload_1
22 getfield #2 <MyTest/Main.i>
25 invokevirtual #6 <java/io/PrintStream.println>
28 return

凡是涉及到数据的getputinvoke,这些操作统统都是操作的常量值池(Constant Pool)。

栈帧所维护的局部变量表

首先要明确的是变量表的显示顺序,参数优先,局部变量其次。

Code
1
2
0	0	29	0	cp_info #19	cp_info #20
1 8 21 1 cp_info #21 cp_info #16

cp_info #19 表示的main方法的参数args。cp_info #20 表示的是局部变量类型,即String类型
cp_info #21 表示的是局部变量arg。cp_info #16 表示的是局部变量的类型,即Main类型。

打赏
  • 微信
    微信
  • 支付宝
    支付宝