虚拟机栈
- 栈是运行时单位,堆是存储的单位;
- 栈解决程序运行问题,如何运行,如何处理数据;
- 堆解决数据如何存放,存放位置;
- 栈中存放一个个栈帧,一个栈帧对应着一个方法;
- 生命周期和线程一致;
- 保存方法的局部变量,部分结果,并参与方法的调用和返回;
异常
-
StackOverflowError
:指定了栈容量大小,线程请求分配的栈容量超过栈允许的最大容量; -
OutofMemoryError
:如果虚拟机栈可以动态扩展,在尝试扩展时没有足够的内存去创建对应的虚拟机栈,会抛出;
设置栈的大小
- 使用
-Xss
来设置:-Xss1024k
;
栈的存储单位
- 栈帧:是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息;
- 线程上每一个方法对应一个栈帧;
- 不同线程的栈帧不可以互相引用;
- 如果当前栈帧调用了其他方法,方法返回之际会将当前栈帧的执行结果给前一个栈帧,然后虚拟机会丢弃当前栈帧,使得前一个栈帧成为当前栈帧;
- Java返回方式:一个是正常返回,一个是抛出异常;都会导致当前栈帧被弹出;
栈帧内部结构
局部变量表
- 定义为一个数字数组,用于存储方法参数和定义在方法体内的局部变量,包含基本数据类型、对象引用、
returnAddress
类型; - 线程私有,不存在数据安全问题;
- 所需要容量在编译器确定下来,运行期间不会改变;
Max local Variables
中存储所需容量; - 局部变量表中的变量值在当前方法调用中有效,栈帧销毁后,局部变量表也会随之销毁;
- 最基本的存储单元是
slot
; - 32位的类型占一个
slot
,64位(long、double
)占两个slot
; -
slot
的槽位可以重复利用; - 局部变量表中的变量是垃圾回收的根节点,只要被局部变量表中直接或者间接引用的对象都不会被回收;
操作数栈
- 使用数组来实现;
- 在方法执行过程当中,根据字节码指令,往栈中写入数据或者提取数据,入栈、出栈;
- 操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间;
- 一个方法刚开始执行的时候,一个新的栈帧也会被随之创建,这个方法的操作数栈是空的;
- 操作数栈只能通过入栈出栈方式进行数据操作;
- 被调用的方法带有返回值的话,其返回值会被压入当前栈帧的操作数栈中;
-
Java
虚拟机的解释引擎是基于栈的执行引擎,其中的栈指的是操作数栈;
动态链接
- 每一个栈帧内部都包含一个指向运行时常量池的方法引用;
- 在
Java
源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用保存在class
文件的常量池中; - 动态链接的作用就是为了
将这些符号引用转换为调用方法的直接引用
;
方法的调用
- 静态链接:当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知,且运行时保持不变。这种情况下将调用方法的符号引用转换为直接引用的过程称为静态链接;
- 动态链接:如果被调用的方法在编译期无法被确定下来,只能够在程序运行期将调用方法的符号引用转换为直接引用,称为动态链接;
- 对应的方法绑定机制为早期绑定、晚期绑定:
- 绑定是指一个字段、方法或者类在符号引用被替换为直接引用的过程,仅发生一次;
-
虚方法和非虚方法:
- 编译器确定了具体的调用版本,版本在运行时不可变。如静态方法、私有方法、final方法、构造器、父类方法都是非虚方法;
- 其他都是虚方法;
- 虚拟机中提供的方法调用指令:
-
invokestatic
:调用静态方法; -
invokespecial
:调用<init>
方法、私有方法以及父类方法; -
invokevirtual
:调用所有虚方法; -
invokeinterface
:调用所有接口方法; -
invokedynamic
:动态解析出需要调用的方法,然后执行;
-
网友评论