1 架构
简单理解:
线程独占区:用来存放执行程序的数据
线程共享区:用来存放对象和类信息等
2 虚拟机栈:
3 执行引擎
通用虚拟机指令执行流程:
- 取指令,其中指令来源于内存
- 译码,决定指令类型(执行何种操作)。另外译码的过程要包括从内存中取操作数
- 执行。指令译码后,被虚拟机执行(其实最终都会借助于物理机资源)
- 存储计算结果
虚拟机的分类
-
基于栈- 可移植
- 速度慢,完成功能指令多
-
基于寄存器
- 依赖寄存器,不容易移植
- 速度快,完成功能指令少
例如执行”a = b + c”:
基于寄存器虚拟机执行该操作只有一条指令:
I1: add a, b, c
在基于栈的虚拟机上字节码指令如下所示:
I1: LOAD C
I2: LOAD B
I3: ADD
I4: STORE A
基于栈的虚拟机:
基于栈的虚拟机有一个操作数栈的概念,虚拟机在进行真正的运算时都是直接与操作数栈(operand stack)进行交互,不能直接操作内存中数据),也就是说不管进行何种操作都要通过操作数栈来进行,即使是数据传递这种简单的操作。可以无视具体的物理架构。
查看字节码指令
public class ByteCodeTest {
public static void main(String[] args) {
System.out.println("Hello World!");
}
public int add() {
int b = 2;
int c = 10;
int a = b + c;
return a;
}
public int add2(int d) {
int b = 2;
int c = 10;
int a = b + c;
return a + d;
}
}
public int add();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: iconst_1 // 把1值推入操作数栈
1: istore_1 // 栈顶出栈并保存到局部变量表Slot1
2: bipush // 把10值推入操作数栈
4: istore_2 // 栈顶出栈并保存到局部变量表Slot2
5: iload_1 //局部变量表Slot1入栈
6: iload_2 //局部变量表Slot2入栈
7: iadd // 将两个栈顶元素出栈,相加,并把结果入栈
8: istore_3 // 栈顶出栈并保存到局部变量表Slot3
9: iload_3 //局部变量表Slot3入栈
10: ireturn
LineNumberTable:
line 11: 0
line 12: 2
line 13: 5
line 14: 9
}
public int add2(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=5, args_size=2
0: iconst_2
1: istore_2
2: bipush 10
4: istore_3
5: iload_2
6: iload_3
7: iadd
8: istore 4
10: iload 4
12: iload_1
13: iadd
14: ireturn
LineNumberTable:
line 18: 0
line 19: 2
line 20: 5
line 21: 10
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this LByteCodeTest;
0 15 1 d I
2 13 2 b I
5 10 3 c I
10 5 4 a I