Jvm字节码执行引擎
概述
从宏观上来说,java虚拟机的执行引擎基本上都是按照输入字节码,字节码解析,输出执行结果.从概念模型上来说,分为方法的调用和字节码的执行.下面详细描述:
运行时的栈桢结构
简介
栈桢是支持方法调用和字节码执行的数据结构.他是虚拟机运行时数据区的虚拟机栈的栈元素.栈桢存储着局部变量表,操作数栈,动态连接和方法返回地址等信息.每一个方法的调用到完成都对应着虚拟机栈的入栈到出栈的过程.在代码编译的时候,栈桢的深度就已经确定了,因此一个栈需要多少内存,不会受到运行期数据的影响.

在活动线程中,只有最顶层的当前栈桢是有效的.引擎中所有的字节码指令都是针对当前栈桢的.
局部变量表
一组变量值存储空间.用于存放方法的参数和方法内部定义的变量.最小单位是slot.一个slot可以存放32位的数据类型,比如:short,byte,boolean,char,float,int,refearce(对象实例的引用).而对于64位的long和double,则会使用2个连续的slot来存储.
注意:java中的long和double都是非原子性的,在32位操作系统上,即读写都是分离的.每次读32位数据.因此在高并发性,需要volatile关键字标注.
但是在局部变量表里面,局部变量表是建立在线程的栈桢上,单线程私有,因此不会要安全问题.
slot顺序:
虚拟机通过索引使用局部变量表.方法在执行时,第0位索引是当前实例变量的引用,即this关键字.其余则会按照顺序排序.
为节省栈桢空间,slot是可以重复使用的.即一个变量即使后续确定不再使用,则也不会立即回收其空间.
对一个变量赋值null使其被回收是没有意义的,因此在经过JIT编译器后,赋值null的操作会被清除掉.
局部变量表没有在类加载准备阶段对变量赋值,因此如果不赋值,会在编译期间报错.
操作数栈
操作栈是一个先入后出的栈.可存储任意类型的数据.32位的栈容量为1,64位的为2.操作栈的深度不会超过max_stacks的值.在方法执行的时候,操作栈是空的,随着方法的执行,不断进行入栈和出栈操作.
例子:int a +int b ,在执行时a和b在栈顶的2个位置,然后字节码指令iadd,栈顶2个元素出栈,则会对其相加,然后将结果入栈.
在概念模型中,两个栈是独立的,但是虚拟机做了一些处理,2个栈可能会共享一部分数据.以便在调用方法时,无需再进行参数的复制传递.称之为:基于栈的执行引擎.

动态连接
每个栈桢都包含一个指向运行期常量池中该栈桢所属方法的引用.这个引用是为了动态连接.
方法返回地址
方法开始执行后,会有2条退出指令.
正常退出:遇到方法返回的字节码指令.栈桢中存储了PC计数器的值,作为返回地址
异常退出: athrow 字节码指令.通过异常处理器表来确定返回地址.
方法调用
方法调用不是方法执行,方法调用唯一的任务是确定调用那个方法.因为在编译阶段,没有连接过程,只是进行了符号引用,而没有真正分配内存布局的入口地址(直接引用).这个特性给java带来了强大的动态加载能力,只有在类加载期间,甚至是执行期间才能确定目标方法的直接引用.
Last updated
Was this helpful?