写在前面
下图是jvm的运行时数据区内存图:
,本文要模拟的是虚拟机栈的相关内存结构的交互过程。
1:正文
因为我们这里模拟的是线程执行方法调用的过程,所以这里先来定义一个线程对象:
java">public class Thread {// 程序计数器 program counterprivate int pc;// 线程虚拟机栈,每个线程都会被分配这样的一块内存区域private JvmStack stack;public Thread(){this.stack = new JvmStack(1024);}public void setStack(JvmStack stack) {this.stack = stack;}public int pc(){return this.pc;}public void setPC(int pc){this.pc = pc;}public void pushFrame(Frame frame){this.stack.push(frame);}public Frame popFrame(){return this.stack.pop();}public Frame currentFrame(){return this.stack.top();}}
这里的JvmStack就是给每个线程分配的线程栈,如下:
java">public class JvmStack {private int maxSize;private int size;// 线程虚拟机栈的方法的当前栈帧private Frame _top;// ...
}
Frame是线程栈的中栈帧,对应线程中的一个方法的调用,如下:
java">public class Frame {//stack is implemented as linked listFrame lower;//局部变量表private LocalVars localVars;//操作数栈private OperandStack operandStack;public Frame(int maxLocals, int maxStack) {this.localVars = new LocalVars(maxLocals);this.operandStack = new OperandStack(maxStack);}public LocalVars localVars(){return localVars;}public OperandStack operandStack(){return operandStack;}}
在栈帧中有一个指向下一个栈帧的引用,这样才能实现一个方法调用另一个方法。LocaVars就是栈帧的局部变量表,OperandStack是栈帧的操作数栈,如下:
java">public class LocalVars {private Slot[] slots;public LocalVars(int maxLocals) {if (maxLocals > 0) {slots = new Slot[maxLocals];for (int i = 0; i < maxLocals; i++) {slots[i] = new Slot();}}}// ...
}
java">public class OperandStack {private int size = 0;private Slot[] slots;public OperandStack(int maxStack) {if (maxStack > 0) {slots = new Slot[maxStack];for (int i = 0; i < maxStack; i++) {slots[i] = new Slot();}}}// ...
}
Slot是一个数据单元,表示在局部变量表以及操作数栈的一个数据项,如下:
java">/*** 本地变量表的数据槽,本地变量表就是一个数据槽组成的数组结构*/
public class Slot {// 槽数据public int num;//public Object ref;@Overridepublic String toString() {return "Slot{" +"num=" + num +", ref=" + ref +'}';}
}
接着我们编写代码来模拟如下代码的执行过程:
java">public class BBB {public static void main(String[] args) {int a = 9;int b = 8;int c = a + b;System.out.println(c);}
}
测试代码:
java">package com.dahuyou;import com.dahuyou.tryy.too.simulate.runtime.area.*;
import com.dahuyou.tryy.too.simulate.runtime.area.Thread;import java.util.Arrays;public class Mm {public static void main(String[] args) {// 模拟创建线程Thread thread = new Thread();// 创建线程的虚拟机栈JvmStack jvmStack = new JvmStack(1000);thread.setStack(jvmStack);// 模拟如下的方法作为当前栈帧/*public void fn() {int a = 9;int b = 8;int c = a + b;}*/// 指定本地变量表大小和操作数栈大小都是10,这里仅仅是测试了,不用在意这个值,jvm实际运行时会根据具体的方法来动态的设置这个值Frame frame = new Frame(10, 10);// 设置本地变量表LocalVars localVars = frame.localVars();localVars.setInt(0, 9);localVars.setInt(1 , 8);// 模拟代码执行过程/*ILOAD 1ILOAD 2IADDISTORE 3*/System.out.println("执行ILOAD 1指令将局部变量表2位置数据压到栈顶");OperandStack operandStack = frame.operandStack();operandStack.pushInt(localVars.getInt(0));System.out.println("执行ILOAD 2指令将局部变量表2位置数据压到栈顶");operandStack.pushInt(localVars.getInt(1));System.out.println("执行IADD指令,从操作数栈弹出2个数据,并执行加法");int param1 = operandStack.popInt();int param2 = operandStack.popInt();int result = param1 + param2;System.out.println("相加后的结果为:" + result);System.out.println("执行ISTORE 3指令将相加后的结果保存到局部变量表槽位3的位置");localVars.setInt(2, result);System.out.println("-----当前局部变量表的数据-----");System.out.println(Arrays.asList(localVars.getSlots()));}
}
运行:
执行ILOAD 1指令将局部变量表2位置数据压到栈顶
执行ILOAD 2指令将局部变量表2位置数据压到栈顶
执行IADD指令,从操作数栈弹出2个数据,并执行加法
相加后的结果为:17
执行ISTORE 3指令将相加后的结果保存到局部变量表槽位3的位置
-----当前局部变量表的数据-----
[Slot{num=9, ref=null}, Slot{num=8, ref=null}, Slot{num=17, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}, Slot{num=0, ref=null}]Process finished with exit code 0
可以看到局部变量表第三个槽位存储的就是计算的结果17
了。
写在后面
参考文章列表
jvm内存结构 。