Java虚拟机栈
存储局部变量表
局部变量存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、 int、float、long、double)、对象引用(reference类型 ,它并不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对相象关的位置) returnAddress类型(指向了一条字节码指令的地址 )。
操作数栈
- 与局部变量表一样,均以字长为单位的数组。不过局部变量表用的是索引,操作数栈是弹栈/压栈来访问。操作数栈可理解为java虚拟机栈中的一个用于计算的临时数据存储区。
- 存储的数据与局部变量表一致含int、long、float、double、reference、returnType,操作数栈中byte、short、char压栈前(bipush)会被转为int。
- 数据运算的地方,大多数指令都在操作数栈弹栈运算,然后结果压栈。
- java虚拟机栈是方法调用和执行的空间,每个方法会封装成一个栈帧压入占中。其中里面的操作数栈用于进行运算,当前线程只有当前执行的方法才会在操作数栈中调用指令(可见java虚拟机栈的指令主要取于操作数栈)。
- int类型在-1~5、-128~127、-32768~32767、-2147483648~2147483647范围分别对应的指令是iconst、bipush、sipush、ldc(这个就直接存在常量池了)
动态连接
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)
Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以指向常量池的引用作为参数。
它主要包括:
在该类中,出现过的各类包,类,接口,字段,方法等元素的全限定名
在JVM中类加载过程中,在解析阶段,Java虚拟机会把类的二级制数据中的符号引用替换为直接引用。
部分符号引用在类加载阶段(解析)的时候就转化为直接引用,这种转化为静态链接。
部分符号引用在运行期间转化为直接引用,这种转化为动态链接。
“因为遇到多态时,类加载期间无法确定最终要调的方法,只有运行时决定要调用哪个类的,所以叫动态,和类加载时候的静态解析对比”
方法出口(方法返回地址)
存放调用方法的程序计数器的值。即调用方法的指令的下一条指令的地址。
如果方法调用正常完成(没有抛出任何异常包括throw显式抛出的异常),当前栈帧承担着恢复调用者状态的责任,包括恢复调用者的局部变量表和操作数栈,以及正确递增程序计数器,以跳过刚才执行的方法调用指令等。被调用方法的返回值会被压入调用者栈帧的操作数栈,然后继续执行。
如果方法调用异常完成(某些指令导致了Java虚拟机抛出异常,且在该方法中没办法处理该异常,或者在执行过程中遇到athrow字节码指令并显式的抛出异常,同时方法内部没有捕获异常),那么一定不会有方法返回值返回给它的调用者。