当前位置: 首页 > 后端技术 > Java

在线面试官:说说Java虚拟机栈?

时间:2023-04-02 00:44:45 Java

对于JVM(JavaVirtualMachine)来说,它有两个非常重要的区域,一个是栈(JavaVirtualMachineStack),另一个是堆。堆是JVM的存储单元,所有的对象和数组都存储在这个区域;而栈是JVM的运行单元,负责Java程序的运行。那么它为什么会有如此神奇的力量呢?它存储什么数据?接下来,我们一起来看看吧。1.栈定义我们先来看栈的定义,我们这里的栈指的是Java虚拟机栈(JavaVirtualMachineStack)也叫做JVM栈,《Java虚拟机规范》对这个区域的说明如下:EachJavaVirtualMachinethreadhas私有的_Java虚拟机堆栈_,与线程同时创建。Java虚拟机堆栈存储帧(§2.6)。Java虚拟机堆栈类似于C等常规语言的堆栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为Java虚拟机堆栈从不直接操作,除了压入和弹出帧外,帧可能是堆分配的。Java虚拟机堆栈的内存不需要是连续的。在Java?虚拟机规范的第一版中,Java虚拟机堆栈被称为Java堆栈。该规范允许Java虚拟机堆栈是连续的固定大小或根据计算需要动态扩展和收缩。如果Java虚拟机堆栈具有固定大小,每个Java虚拟机堆栈的大小可以在创建堆栈时独立选择。Java虚拟机实现可以为程序员或用户提供对Java虚拟机堆栈初始大小的控制,以及,在动态扩展或收缩Java虚拟机堆栈的情况下,控制最大和最小大小。以下异常情况与Java虚拟机堆栈相关:如果线程中的计算需要比允许的更大的Java虚拟机堆栈,Java虚拟机抛出StackOverflowError。如果Java虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存可用于实现扩展,或者如果没有足够的内存可用于创建初始Java虚拟机stackforanewthread,theJavaVirtualMachinethrowsanOutOfMemoryError.以上内容翻译成中文意思是这样的:Java虚拟机栈是线程私有的区域,随着线程的创建而创建。它存储局部变量表(基本数据类型和对象引用地址)和计算过程中的中间结果。Java虚拟机的内存不需要是连续的,它只有两个操作:push和pop。Java虚拟机栈要么大小固定,要么根据计算动态扩缩。程序员可以设置Java虚拟机栈的初始值和最大值。Java虚拟机栈异常有两种:当Java虚拟机栈大小固定时,如果程序中的栈分配超过最大虚拟机栈,就会出现StackOverflowError异常。如果Java虚拟机栈是动态扩展的,那么当内存不足时,就会抛出OutOfMemoryError异常。2.栈结构栈是线程私有的。每个线程都有自己的堆栈(空间)。栈中的数据以栈帧(StackFrame)的形式存在。线程会生成一个Stackframe,如下图所示:PS:当调用一个新的方法时,会在stack上创建一个stackframe,当方法调用完成时,表示stackframe会执行堆栈操作。而栈帧中存放了5个内容:局部变量表(LocalVariables);操作(数)栈(OperandStack);动态链接(DynamicLinking);方法返回地址(ReturnAddress);附加信息。如下图所示:栈的整体存储结构如下图所示:2.1局部变量表局部变量表也称为局部变量数组或局部变量表。局部变量表是一个数组,里面存放:方法??参数;方法中的局部变量,即方法中的基本数据类型和对象引用(Reference);方法返回类型(返回地址)。接下来我们通过类生成的字节码来观察局部变量表的内容。首先,让我们创建一个main方法。具体代码如下:publicstaticvoidmain(String[]args){intnum=0;LocalVariablesExamplelv=newLocalVariablesExample();}然后我们编译类,然后使用“javap-vLocalVariablesExample.class”查看字节码生成的内容,其中包含局部变量表的内容如下:我们也可以通过JClassLib观察局部变量表局部变量表的长度如下图所示:局部变量表的详细信息如下:2.2操作栈操作栈也称为操作数栈或表达式栈。操作数栈主要用来保存计算过程的中间结果。同时在计算过程中作为变量的临时存储空间。思考:为什么程序执行过程中的中间结果不保存在局部变量表中,而是保存在操作数栈中呢?因为局部变量表是一个数组,而数组的长度在创建的时候就已经确定了,所以局部变量表的内容和大小是由编译器决定的,所以程序执行中的这些动态中间结果需要新的空间来保存,而操作数栈就可以实现这个功能。2.3动态链接动态链接也称为指向运行时常量池的方法引用。这个区域的概念和作用有点难理解。每个堆栈帧都包含对运行时常量池中堆栈帧所属方法的引用。当一个方法调用另一个方法时,在常量池中用指向该方法的符号引用来表示,那么动态链接的作用就是将这些符号引用转化为对调用方法的直接引用。也就是说:当一个方法调用另一个方法时,不会创建被调用的方法,而是通过常量池的方法引用来调用,而这个区域存放的是运行时常量池的方法引用,这个区域的作用就是将运行时常量池的符号引用转为直接引用。2.4方法返回地址方法返回地址也称为方法正常退出或异常退出的定义。方法返回地址存储调用该方法的程序计数器的值。程序计数器存储线程要执行的下一行指令的位置。也就是说:一个方法中调用了另一个方法,被调用的方法执行完后,下一行要执行的指令就保存在这个区域。2.5附加信息这个区域在很多教程中都被省略了,因为这个区域可能有也可能没有数据。这些附加信息是Java虚拟机实现相关的一些信息。例如,为程序调试提供支持的信息。总结作为Java虚拟机的核心组件之一,栈包括以下五个部分:局部变量:主要存放方法中的基本数据类型和对象引用;运算(数)栈(OperandStack):主要用于保存计算过程的中间结果,同时作为计算过程中变量的临时存储空间;动态链接(DynamicLinking):存储指向运行时常量池的方法引用;方法返回地址(ReturnAddress):存放调用该方法的程序计数器的值;someadditionalinformation:存放一些Java虚拟化相关的数据,比如程序调试数据。Reference&Acknowledgments《阿里巴巴Java开发手册》《尚硅谷JVM》本文已收录在Gitee开源仓库《Java 面试指南》,其中包括:Redis、JVM、并发、并发、MySQL、Spring、SpringMVC、SpringBoot、SpringCloud、MyBatis、设计模式、消息队列和其他模块。Java面试就够了:超全Java常见面试题,持续更新中...