java虚拟机——栈帧结构
1.总述栈帧
java虚拟机以方法作为基本的执行单元。这个执行单元的数据结构就是 虚拟机栈 中的 栈元素——栈帧。
栈帧的结构如下:
如上图所示,栈帧存储了方法的局部变量表,操作数栈,动态连接、方法返回地址和一些额外的附加信息。
对于虚拟机的执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是生效的,即只有当前栈帧是生效的,与当前栈帧关联的方法叫当前方法。执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。
在编译java源码时,栈帧中需要多大的局部变链表,操作数栈的深度这些已经被分析出来并写到了方法表的Code属性中了,如下图是一个main方法的栈帧中的局部变量表大小等数据:
2.局部变量表
局部变量表中存放方法的局部变量。java源码被编译为Class文件时,某个方法的局部变量表的大小就已经确定在了该方法Code的属性中了 。
局部变量表的容量以变量槽 variable slot 为最小单位。
java虚拟机规范规定,变量槽能存放下一个byte,int ,char,reference,等8种数据类型。这8种数据类型除过reference都是没有超过32位的。reference是一个对象的引用,虚拟机没有明确规定其长度,其是32还是64位取决于虚拟机本身是32位还是64位的。
java虚拟机中明确规定的64位长度的数据类型只有long和double,当存储这个类型的变量时,会分配2个连续的变量槽来存储。由于局部变量表是虚拟机栈中的,是线程的私有变量,因此无论读写2个连续的变量槽是否是原子操作,都不会引起数据竞争和线程安全问题。
对于使用2个相邻的变量槽来存在一个64位数据,java虚拟机不允许以任何方式单独访问其中的一个变量槽,必须2个一起访问。
局部变量和之前的类变量有一个很大的差异:
类的字段变量有2次赋初值的过程:准备阶段会赋初值,初始化阶段,赋予程序代码定义的初始值。因此,在写代码时,即使没有为类变量赋初值也是可以使用的,因为在准备阶段会自动为其赋一个初值。
局部变量如果在程序里没有赋值,则是完全不能使用的。