Jvm内存中栈分两种:本地方法栈 和 虚拟机栈。两者没有本质上的区别,区别在于服务的对象不同。本地方法栈服务于JVM虚拟机的native方法,如JDK安装目录下很多C的文件实现的方法,这些就是native方法。虚拟机栈服务于虚拟机执行的Java方法。
一、栈帧
栈帧其实就是栈里面的元素,用于支持Java虚拟机进行方法调用和方法执行背后的数据结构。了解它就可以更好地理解Java虚拟机执行引擎是如何运行的。
- 一个线程对应一个虚拟机栈,当前CPU调度的那个线程叫做活动线程。
- 每个方法被执行时会创建一个栈帧(Stack Frame),进入虚拟机栈,一个栈帧对应一个方法;
- 每个方法结束对应着栈帧的出栈,入栈表示被调用,出栈表示执行完毕或者返回异常;
- 栈帧是一个数据结构,所以用于存储局部变量表(Local Variable)、操作数栈(Operand Stack)、动态链接(Dynamic Link)、方法出口(Return Address)等信息;
- 活动线程的虚拟机栈里最顶部的栈帧代表当前正在执行的方法,这个栈帧也被叫做"当前栈帧"。
- 在同一时刻、同一条线程中,只有位于栈顶的方法才是在运行的,只有位于栈顶的栈帧才是生效的,执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。
虚拟机栈和栈帧的结构如图:
栈帧的部分信息,如局部变量表、操作数栈、运行时常量池可以通过JVM字节码查看:
javap -v 类名
public class ShowJOL {
public static volatile int a = 3;
public static void main(String[] args) {
a = 5;
}
}
// 执行javap -p ShowJOL
Classfile /Users/shaotuo/java/java/target/classes/edward/com/ShowJOL.class
Last modified 2022-3-15; size 474 bytes
MD5 checksum 19d688ea832ca46ef13267208f9d22e1
Compiled from "ShowJOL.java"
public class edward.com.ShowJOL
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#21 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#22 // edward/com/ShowJOL.a:I
#3 = Class #23 // edward/com/ShowJOL
#4 = Class #24 // java/lang/Object
#5 = Utf8 a
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this