关于Java虚拟机栈局部变最表slot的理解

局部变最表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在 Java程序被编译为 Class文件时,就在方法的 Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。

局部变量表的容量以变量槽(variable slot,下称slot)为最小单位,虚拟机规范中并没有明确指明一个slot应占用的内存空间大小,只是很有“导向性”地说明每个slot都应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据,这种描述与明确指出“每个slot占用32位长度的内存空间”有一些差别,它允许slot的长度随着处理器、操作系统或虚拟机的不同而发生变化。不过无论如何,即使在64位虚拟机中使用了64位长度的内存空间来实现一个slot,虚拟机仍要使用对齐和补白的手段让slot在外观上看起来与32位虚拟机中的一致。

既然前面提到了数据类型,在此顺便说一下,一个slot可以存放一个32位以内的数据类型,Java中占用32位以内的数据类型有boolean、byte、char、short、int、float、refcrcnce和retumAddress八种类型.前面六种不需要多加解释,大家都认识,而后面的referencc是对象的引用。虚拟机规范既没有说明它的长度,也没有明确指出这个引用应有怎样的结构,但是一般来说,虚拟机实现至少都应当能从此引用中直接或间接地查找到对象在Java堆中的起始地址索引和方法区中的对象类型数据。而:etumAddress是为字节码指令jsr、jsr_w和ret服务的,它指向了一条字节码指令的地址。

对于64位的数据类型,虚拟机会以高位在前的方式为其分配两个连续的slot空间。Java语言中明确规定的64位的数据类型只有long和double两种(reference类型则可能是32位也可能是64位)。值得一提的是,这里把long和double数据类型分割存储的做法与“long和double的非原子性协定”中把一次long和double数据类型读写分割为两次32位读写的做法类似,读者阅读到Java内存模型时可以对比一下。不过,由于局部变量表建立在线程的堆栈上,是线程私有的数据,无论读写两个连续的 slot 是否是原子操作,都不会引起数据安全问题。

虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始到局部变量表最大的slot数量。如果是32位数据类型的变量,索引n就代表了使用第n个slot, 如果是64位数据类型的变量,则说明要使用第n和第n+l两个slot。在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程的,如果是实例方法(非 static的方法),那么局部变量表中第0位索引的slot默认是用于传递方法所属对象实例的引用,在方法中可以通过关键字“this”来访问这个隐含的参数。其余参数则按照参数表的顺序来排列,占用从1开始的局部变量slot,参数表分配完毕后,再根据方法体内部定义的变量顺序和作用域分配其余的slot。
局部变量表中的slot是可重用的,方法体中定义的变量,其作用域并不一定会覆盖整个方法体,如果当前字节码PC计数器的值已经超出了某个变量的作用域,那么这个变量对应的slot就可以交给其他变量使用。这样的设计不仅仅是为了节省栈空间,在某些情况下slot的复用会直接影响到系统的垃圾收集行为。
局部变量不像成员变量在定义的时候赋初始值。
变量槽slot的理解与演示

  1. 参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束
  2. 局部变量表,最基本的存储单元是Slot(变量槽)
  3. 局部变量表中存放编译期可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量。
  4. 在局部变量表里,32位以内的类型只占用一个slot(包括returnAddress类型),64位的类型(long和double)占用两个slot。byte、short、char、float在存储前被转换为int,boolean也被转换为int,0表示false,非0表示true;long和double则占据两个slot。
  5. JVM会为局部变量表中的每一个slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值
  6. 当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照声明顺序被复制到局部变量表中的每一个slot上
  7. 如果需要访问局部变量表中一个64bit的局部变量值时,只需要使用前一个索引即可。(比如:访问long或者double类型变量)
  8. 如果当前帧是由构造方法或者实例方法创建的(意思是当前帧所对应的方法是构造器方法或者是普通的实例方法),那么该对象引用this将会存放在index为0的slot处,其余的参数按照参数表顺序排列。
  9. 静态方法中不能引用this,是因为静态方法所对应的栈帧当中的局部变量表中不存在this
  10. slot的数量保持不变
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
由以上可以看出,slot的数量保持不变,b变量出了它的作用域之后就没有了,c变量占用b的Slot

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章