JVM初探之 Java虚拟机栈

6 篇文章 0 订阅

在这里插入图片描述

Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表操作数栈动态连接方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。(HotSpot虚拟机的栈不会动态扩展,远古时期的Classic可以)

Java虚拟机栈主要包括一下四大部分:

局部变量表

局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(八大基本类型)、对象引用(reference类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(返回地址:指向了一条字节码指令的地址)。(即:基本数据类型直接存值,引用类型存的是对象的引用

这些数据类型在局部变量表中的存储空间以局部变量槽(Slot) 来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。

局部变量表中的局部变量是不存在像类装载子系统中的连接阶段的准备阶段的,因此对于下面这段代码,类变量b可以输出为0,而局部变量a则无法通过编译:

public class Main {
    static int b;

    public static void main(String[] args) throws Throwable {
        int a;
        System.out.println(a);
        System.out.println(b);
    }
}

在这里插入图片描述

操作数栈

当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。

操作数栈的每一个元素都可以是包括long和double在内的任意Java数据类型。32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2。

动态链接

在Java源文件被编译到字节码文件时,所有的变量和方法引用都作为符号引用(Symbilic Reference)保存在方法区的运行时常量池中。.

静态链接:Java类加载器的连接中的解析阶段负责将符号引用替换为直接引用,是在编译时完成的。
动态链接:碰到多态时,静态链接无法在编译时将符号引用替换为在直接引用,因此需要动态链接在运行时将符号引用替换为在直接引用。

比如,描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。

方法出口

当一个方法执行的时候,只有两种可以退出方法的方法。第一种是JVM碰到任意一个方法返回的字节码指令(return),被称为正常完成出口。另一种是在执行方法中抛出异常并且未对异常进行处理,被称为异常完成出口。方法退出的时候相当于把栈帧出栈。

无论采用何种退出方式,在方法退出之后,都必须返回到最初方法被调用时的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层主调方法的执行状态。一般来说,方法正常退出时,主调方法的PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中就一般不会保存这部分信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值