运行时数据区和指令
1.JVM运行时数据区(JVM Runtime Data Area)#
1.1 Program Counter (程序计数器)#
Each Java Virtual Machine thread has its own pc (program counter) register
每个java虚拟机线程都有自己的PC(程序计数器)寄存器
At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method for that thread
在任何时候,每个java虚拟机线程都在执行单一的方法代码,既该线程的当前方法
If that method is not native , the pc register contains the address of the Java Virtual Machine instruction currently being executed
如果该方法不是本地方法,则PC(程序计数器)寄存器包含当前正在执行的java虚拟机指令的地址
1.2 JVM Stack(线程私有)#
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread
每个java虚拟机线程都有一个私有java虚拟机栈,与线程同时创建
A Java Virtual Machine stack stores frames
java虚拟机栈里存储帧
- Frame - 每个方法对应一个栈帧,栈桢结构:
本地变量表(Local Variable Table)
在编译程序代码的时候就可以确定栈帧中需要多大的局部变量表,具体大小可在编译后的 Class 文件中看到。
局部变量表的容量以 Variable Slot(变量槽)为最小单位,每个变量槽都可以存储 32 位长度的内存空间。
在方法执行时,虚拟机使用局部变量表完成参数值到参数变量列表的传递过程的,如果执行的是实例方法,那局部变量表中第 0 位索引的 Slot 默认是用于传递方法所属对象实例的引用(在方法中可以通过关键字 this 来访问到这个隐含的参数)。其余参数则按照参数表顺序排列,占用从 1 开始的局部变量 Slot。
基本类型数据以及引用和 returnAddress(返回地址)占用一个变量槽,long 和 double 需要两个。
操作数栈(Operand Stack)
同样也可以在编译期确定大小
Frame 被创建时,操作栈是空的。操作栈的每个项可以存放 JVM 的各种类型数据,其中 long 和 double 类型(64位数据)占用两个栈深。
方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈和入栈操作
操作栈调用其它有返回结果的方法时,会把结果 push 到栈上(通过操作数栈来进行参数传递)
动态链接(Dynamic Linking)
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。
在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析。另外的一部分将在运行时转化为直接引用,这部分称为动态链接。
返回地址(Return Address)
方法开始执行后,只有 2 种方式可以退出 :方法返回指令,异常退出。
a() -> b(),方法a调用了方法b, b方法的返回值放在什么地方
- 栈帧操作详解:
public class TestIPulsPlus {
public static void main(String[] args) {
int i = 8;
i = i++;
System.out.println(i); // 输出结果为8,个人最开始觉得是9
}
}
- 对应的本地变量表:
执行过程分析:
bipush 8 将8压栈
istore_1 将栈顶数据出栈并把值设置给本地变量表中index为1的变量,就是将i=8
iload_1 将本地变量表中index为1的变量值压栈
iinc 1 by 1将本地变量表中index为1的变量值+1
istore_1 将栈顶数据出栈并把值设置给本地变量表中index为1的变量,这个操作会把上一步+1操作的值又覆盖为8
1.3 Heap(线程共享)#
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads.
Java虚拟机有一个堆,在所有Java虚拟机线程之间共享。
The heap is the run-time data area from which memory for all class instances and arrays is allocated.
堆是运行时数据区域,所有类实例和数组都从这里分配内存。
1.4 Method Area(线程共享)#
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.
Java虚拟机有一个在所有Java虚拟机线程之间共享的方法区域。
It stores per-class structures
它存储每个类的结构,比如T.Class信息
Runtime Constant Pool 在Method Area中(A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file
每个类或每个接口的运行时常量池是类文件中constant_pool表所表示
JDK < 1.8
方法区的实现叫Perm Space
字符串常量位于Perm Space
FGC不会清理
大小启动的时候指定,不能变
JDK >= 1.8
方法区的实现叫Meta Space
会触发FGC清理
不设定的话,最大就是物理内存
1.5 Native Method Stack (线程私有)#
An implementation of the Java Virtual Machine may use conventional stacks called native method stacks
Java虚拟机的实现可以使用称为本机方法堆栈的传统堆栈
1.6 Direct Memory#
JVM可以直接访问的内核空间的内存 (OS 管理的内存)
NIO , 提高效率,实现zero copy
2.JVM指令#
store 出栈
load 压栈
pop 将栈顶数值弹出 (数值不能是long或double类型的)
mul 将栈顶两数值相乘并将结果压入栈顶
sub 将栈顶两数值相减并将结果压入栈顶
invokeStatic 调用静态方法
invokeVirtual 普通方法调用
invokeInterface List list = new ArrayList<>(); list.add()
inovkeSpecial 可以直接定位,不需要多态的方法private 方法 , 构造方法
invokeDynamic JVM最难的指令,lambda表达式或者反射或者其他动态语言scala kotlin,或者CGLib ASM,动态产生的class,会用到的指令
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端