When the execution engine in the JVM executes java code, it generally has two options: interpreted execution (execution through an interpreter) and compiled execution (local code execution generated through a just-in-time compiler).
Stack frame
Definition:
Stack frame is data used to support method calling and method execution by the virtual machine Structure, which is located inside the virtual machine stack.
Function:
Every method from the beginning of the call to the completion of execution corresponds to a stack frame from the stack to the stack in the virtual machine stack. the process of.
Features:
(1) The stack frame includes the local variable table, operand stack, etc. How big is it needed? The local variable table and the depth of the operand stack are determined at compile time. Because how much memory needs to be allocated for a stack frame will not be affected by variable data during program runtime.
(2) Data sharing between two stack frames. In the conceptual model, the two stack frames are completely independent, but in the implementation of the virtual machine, some optimization processing will be done to partially overlap the two stack frames. In this way, part of the data can be shared when making method calls, without the need for additional parameter copying and passing.
(1) Local variable table
The local variable table is a set of variable value storage spaces. Used to store method parameters and local variables defined within the method.
//方法参数 max(int a,int b)
int a;//全局变量 void say(){ int b=0;//局部变量 }
Local variables are different from class variables (variables modified with static)
Class variables have two processes of assigning initial values: the preparation phase (assigning the system initial value) and the initialization phase (assigning Programmer-defined initial value). So it doesn't matter even if the class variable is not assigned a value during the initialization phase, it still has a certain initial value.
But local variables are different. If they are defined but not assigned an initial value, they cannot be used.
(2) Operation stack
When a method just starts executing, the operand stack of this method is empty. During the execution process, there will be various bytecode instructions to write and extract content from the operand stack, that is, pop and push operations.
For example, calculate:
int a=2+3
The two elements closest to the top of the operand stack are 2 and 3. When the iadd instruction is executed, 2 and 3 will be popped off the stack and added. , and then push the added result 5 onto the stack.
(3) Dynamic link
#There are a large number of symbol references in the constant pool of the Class file, and method calling instructions in the bytecode Just take a symbolic reference to the method in the constant pool as a parameter. These symbol references are divided into two parts:
Static analysis: converted into direct references during the class loading phase or when used for the first time. Dynamic link: converted into a direct reference during each run.
(4) Return address
当一个方法开始执行后,只有两种方式可以退出这个方法:正常退出、异常退出。无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行。
当方法正常退出时
调用者的PC计数器作为返回地址。栈帧中一般会保存这个计数器值。
当方法异常退出时
返回地址是要通过异常处理器表来确定的。栈帧中一般不会保存这部分信息。
方法调用
方法调用是确定调用哪一个方法。
(1)解析
对“编译器可知,运行期不可变”的方法进行调用称为解析。符合这种要求的方法主要包括
静态方法,用static修饰的方法私有方法,用private修饰的方法
(2)分派
分派讲解了虚拟机如何确定正确的目标方法。分派分为静态分派和动态分派。讲解静动态分派之前,我们先看个多态的例子。
Human man=new Man();
在这段代码中,Human为静态类型,其在编译期是可知的。Man是实际类型,结果在运行期才可确定,编译期在编译程序的时候并不知道一个对象的实际类型是什么。
静态分派:
所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。它的典型应用是重载。
public class StaticDispatch{ static abstract class Human{ } static class Man extends Human{ } static class Woman extends Human{ } public void say(Human hum){ System.out.println("I am human"); } public void say(Man hum){ System.out.println("I am man"); } public void say(Woman hum){ System.out.println("I am woman"); } public static void main(String[] args){ Human man = new Man(); Human woman = new Woman(); StaticDispatch sr = new StaticDispatch(); sr.say(man); sr.say(woman); } }
运行结果是:
I am human I am human
为什么会产生这个结果呢?
因为编译器在重载时,是通过参数的静态类型而不是实际类型作为判断依据的。在编译阶段,javac编译器会根据参数的静态类型决定使用哪个重载版本,所以两个对say()方法的调用实际为sr.say(Human)。
动态分派:
在运行期根据实际类型确定方法执行版本的分派过程。它的典型应用是重写。
public class DynamicDispatch{ static abstract class Human{ protected abstract void say(); } static class Man extends Human{ @Override protected abstract void say(){ System.out.println("I am man"); } } static class Woman extends Human{ @Override protected abstract void say(){ System.out.println("I am woman "); } } public static void main(String[] args){ Human man = new Man(); Human woman = new Woman(); man.say(); woman.say(); man=new Woman(); man.say(); } }
运行结果:
I am man I am woman I am woman
这似乎才是我们平时敲的java代码。对于方法重写,在运行时才确定调用哪个方法。由于Human的实际类型是man,因此调用的是man的name方法。其余的同理。
动态分派的实现依赖于方法区中的虚方法表,它里面存放着各个方法的实际入口地址。如果某个方法在子类中被重写了,那子类方法表中的地址将会替换为指向子类实现版本的入口地址,否则,指向父类的实现入口。
单分派和多分派:
方法的接收者与方法的参数统称为方法的宗量,根据分派基于多少种宗量,分为单分派和多分派。
在静态分派中,需要调用者的实际类型和方法参数的类型才能确定方法版本,所以其是多分派类型。在动态分派中,已经知道了参数的实际类型,所以此时只需知道方法调用者的实际类型就可以确定出方法版本,所以其是单分派类型。综上,java是一门静态多分派,动态单分派的语言。
字节码解释执行引擎
虚拟机中的字节码解释执行引擎是基于栈的。下面通过一段代码来仔细看一下其解释的执行过程。
public int calc(){ int a = 100; int b = 200; int c = 300; return (a + b) * c; }
第一步:将100入栈。
Step 2: Pop 100 from the operation stack and store it in local variables. The same applies to the subsequent 200,300.
Step 3: Copy 100 in the local variable table to the top of the operand stack.
Step 4: Copy 200 in the local variable table to the top of the operand stack.
Step 5: Pop 100 and 200 off the stack, perform integer addition, and finally push the result 300 back onto the stack.
Step 6: Copy the third number 300 from the local variable table to the top of the stack. The next step is to pop the two 300s off the stack, perform integer multiplication, and push the final result 90000 onto the stack.
Step 7: The method ends and the integer value at the top of the operand stack is returned to the caller of this method.
The above is a complete introduction to the JAVA virtual machine-bytecode execution engine. For more related questions, please visit the PHP Chinese website: JAVA Video Tutorial
The above is the detailed content of Detailed introduction to JAVA Virtual Machine (JVM) (6) - bytecode execution engine. For more information, please follow other related articles on the PHP Chinese website!