PC程序计数器
每一个线程都要有一个pc,用于存放指令位置,虚拟机的运行,类似于这样的循环:
while(方法未执行结束) {
取PC中的位置,找到对应位置的指令;
执行该指令;
PC ++;
}
JVM Stack虚拟机栈
每一个线程对应一个栈,每个方法对应一个栈帧Frame
- Local Variable Table 局部变量表:存放局部变量信息,局部变量表示方法内部使用到的变量,除了通常理解的局部变量之外,还包括方法参数和非static方法的this;
- Operand Stack 操作数栈:存放中间数据
- Dynamic Linking 动态链接:指向运行时常量池的符号链接,方法名是啥,方法类型是啥,没解析就动态解析,已经解析就直接使用。
- return address:表示方法返回地址,即
a() -> b()中。b方法返回值存放地址。
一个无聊的例子:
public static void main(String[] args) {
int i = 8;
i = i++;
// i = ++i;
System.out.println(i);
}
此时局部变量表中存储的是:
| 下标 | 局部变量 |
|---|---|
| 0 | args |
| 1 | i |
i = i++的情况下反编译代码如下:
0 bipush 8 // 8压栈
2 istore_1 // 弹出栈顶值(8)给局部变量表下标为1的位置(i)
3 iload_1 // 局部变量表下标为1(i)的值压栈
6 iinc 1 by 1 // 局部变量表为1(i)的值+1 即8+1
7 istore_1 // 栈顶的值(8)再赋值回局部变量表为1的位置(i) 即最终为8
8 return
i = ++i的情况反编译代码如下:
0 bipush 8
2 istore_1
3 iinc 1 by 1
6 iload_1
7 istore_1
8 return
// TODO 更复杂的方法解析
Heap堆
可以看下这篇文章juejin.cn/post/687267…
Method Area方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- Perm Space (jdk < 1.8) 永久区:
- 字符串常量位于PermSpace
- FGC不会清理
- 大小启动的时候指定,不能变
- Meta Space (jdk >= 1.8) 元空间:
- 字符串常量位于堆
- 会触发FGC清理
- 不设定的话,最大就是物理内存
Native Method Stack本地方法栈
- 本地方法可以通过JNI(Java Native Interface)来访问虚拟机运行时的数据区
- 存放C C++方法等
Direct Memory 直接内存
JVM可以直接访问的内核空间的内存(OS管理的内存),用于NIO,实现零拷贝。