4.3局部变量表
4.3局部变量表
局部变量表也称为局部变量数组或本地变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型。
由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题。
局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。
方法嵌套调用的次数由栈的大小决定。一般来说,栈越大,方法嵌套调用次数越多。对一个函数而言,它的参数和局部变量越多,使得局部变量表膨胀,它的栈帧就越大,以满足方法调用所需传递的信息增大的需求。进而函数调用就会占用更多的栈空间,导致其嵌套调用次数就会减少。
局部变量表中的变量只在当前方法调用中有效,在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。
4.3.1Slot变量槽
参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束。
局部变量表最基本的存储单元是Slot(变量槽)
局部变量表中存放编译期可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量。
在局部变量表里,32位以内的类型只占用一个Slot(包括returnAddress类型),64位的类型(long和double)占用两个slot。
byte、short、char、float在存储前被转换为int,boolean也被转换为int,0表示false,非0表示true。
long和double则占据两个slot。
JVM会为局部变量表中的每一个Slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值。
当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个Slot上。
如果需要访问局部变量表中一个64bit的局部变量值时,只需要使用前一个索引即可。(比如:访问long或double类型变量)
如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将会存放在index0的Slot处,其余的参数按照参数表顺序继续排列。
Slot的重复利用:
栈帧中的局部变量表中的槽位是可以复用的,如果一个局部变量超过其作用域,那么在其作用域之后申明的新的局部变量就很有可能会复用过期局部变量槽位,从而达到节省资源的目的。
public class SlotTest { public void localVarl() { int a = 0; System.out.println(a); int b = 0; } public void localVar2() { // 变量a的作用域在{}内,执行过后,变量a失效 { int a = 0; System.out.println(a); } // 此时的b就会复用a的槽位 int b = 0; double c = 0; char d = 'a'; } }
SlotTest.class字节码localVar2()栈帧的局部变量表:
4.3.2静态变量与局部变量的对比
参数表分配完毕之后,再根据方法体内定义的变量的顺序和作用域分配。
我们知道类变量表有两次初始化的机会,第一次是在"准备阶段",执行系统初始化,对类变量设置零值,另一次则是在"初始化"阶段,赋予我们在代码中定义的初始值。
和类变量初始化不同的是,局部变量表不存在系统初始化的过程,这意味着一旦定义了局部变量则必须赋予初始值,否则无法使用。
public class Test { public void test() { int i; // 错误使用局部变量i,局部变量没有赋值不能使用 System.out.println(i); } }
在栈帧中,与性能调优关系最为密切的部分就是前面提到的局部变量表。在方法执行时,虚拟机使用局部变量表完成方法的传递。
局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收
本文来自博客园,作者:Lz_蚂蚱,转载请注明原文链接:https://www.cnblogs.com/leizia/p/15383235.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步