JVM的虚拟机栈
虚拟机栈是线程的私有内存,栈中的元素被称为栈帧, 方法被调用时,就会往线程的虚拟机栈中压入新的栈帧,栈帧中包含有方法调用的相关信息,如局部变量表(包含方法参数和方法体内定义的局部变量)、操作数栈、方法返回信息等;栈顶的栈帧代表了当前正在被调用的方法,当方法返回时,栈顶的栈帧元素被弹出,从方法的调用到返回对应了栈顶元素的入栈到出栈的过程.
栈桢结构
虚拟机栈中是由栈桢组成的,方法的每次调用到退出的过程对应了栈桢在虚拟机栈中的入栈到出栈的过程,当前正在被执行的方法对于栈顶的栈桢,也被称为是当前栈桢.
栈桢中包含了方法运行所需要的全部信息,主要包括局部变量表、操作数栈、动态链接以及方法出口信息等, 如下图所示
1. 局部变量表
局部变量表包括方法参数以及在方法内部定义的局部变量(由于栈桢元素是线程私有的,因此如果某个方法只依赖于方法参数和局部变量的话,那它一定是线程安全的)
局部变量表是以变量槽(slot)为最小单位,JVM并没有指明每个slot占用的内存大小; 在方法执行的时候,虚拟机是通过局部变量表完成方法参数值到参数变量的传递,对于非静态方法(static)来讲,第一个槽存放的是this变量,然后是方法参数的值,接着是方法内部定义的局部变量的值
2. 操作数栈
通常会听到有人说“JAVA是基于栈的执行引擎”, 这里说的栈就是操作数栈. 它是一个“后进先出” (LIFO)的栈结构, 栈中的元素为操作数,虚拟机的操作指令都是针对操作数栈中的元素来进行的。在方法刚开始执行的时候,操作数栈是空的,随着方法的执行,虚拟机会将操作指令的操作数入栈,然后执行相应的指令,再从栈中读取数据(出栈).
例如, iadd指令是对两个操作数进行加操作,在执行这条指令的时候,虚拟机会将要相加的两个操作数进行入栈操作,然后执行iadd, iadd会将栈顶的两个元素进行相加后再将结果进行入栈.
3. 动态链接
动态链接的作用是,每个栈帧都会包含指向运行时常量池中当前栈帧对应的方法的引用. 持有方法的引用 是为了支持动态链接(?)
4. 返回地址
当方法被执行时,返回的方式有两种: 一种是正常的操作指令退出, 一种是因为程序异常(不管是虚拟机异常还是未捕获异常)导致的程序退出; 不管是何种方式退出, 程序都会返回到调用该方法的位置;程序退出的过程相当于栈桢出栈的过程,因此可能的操作包括恢复上层方法的局部变量表和操作数栈、把返回值压入上层调用方法的操作数栈中以及恢复程序计数器的值等