虚拟机字节码执行引擎
执行引擎在执行JAVA代码的时候可以选择解释执行(通过解释器执行)和编译执行(通过即使编译器产生本地代码执行)两种选择。
?
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。栈帧存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息。每一个方法调用的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
?
一个线程中的方法调用链可能很长,很多方法都同时处于执行状态,对于执行引擎来说,活动线程中,只有栈顶的栈帧是有效的,成为Curent Stack Frame。 这个栈帧所关联的方法称为当前方法(Current Method)。执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。
?
局部变量表
用于存放方法参数和方法内部定义的局部变量,在编译成CLASS文件时,就在方法的CODE属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。
?
局部变量表的容量以变量槽(Variable Slot)为最小单位,虚拟机规范中并没有明确指出一个slot应占用的内存空间大小。
?
一个Slot可以存放一个32位以内的数据类型,这些类型有:boolean,byte,char,short,int,float,reference和returnAddress。returnAddress是为字节码指令jsr,jsr_w和ret服务的,指向下一条字节码的地址。
?
对于64位数据,JVM会以高位在前的方式分配两个连续的Slot空间。
JAVA明确规定的64位数据只有long和double两种。reference可能是32也可能是64位
?
JVM通过索引定位的方式使用局部变量表,索引值的范围从0开始到局部变量表最大的SLOT数量。
?
在方法执行时,JVM使用局部变量表完成参数值到参数变量列表的传递过程。如果是实例方法,那么局部变量表的第0位索引的SLOT默认是用于传递方法所属对象实例的引用,在方法中可以通过“this"访问到这个隐含的参数。其余参数则按照参数表的顺序排列,参数表分配完毕后,再根据方法体内部定义的变量顺序和作用于分配其余SLOT。
?
局部变量表中的SLOT是可以重用的,如果当前字节码PC计数器的值已经超出了某个变量的作用域,那么这个变量对应的SLOT就可以交给其他变量使用。
?
?
0: new #16;3; dup4: invokespecial #18;7; astore_18: new #19;11:dup12:invokespecial #21;15:astore_216:aload_117:invokevirtual #22;20:aload_221:invokevirtual #22;24:new #19;27:dup28:invokespecial #21;31:astore_132:aload_133:invokevirtual #2236:return?0-15行是准备工作,用于生成对象,初始化对象,并将两个实例存放在第一和第二个局部变量表slot中。16和20行分别将刚创建的两个对象引用压到栈顶,这两个对象是将要执行的sayHello()方法的所有者,成为接收者。17和21行是方法调用指令,可见指令和参数都是一样的,都是invokevirtual常量池中第22项的常量---Human.sayHello()的符号引用,而结果是这两次调用的结果不同,原因是invokevirtual指令的运行时解析过程:
?