前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM-虚拟机栈(局部变量表)

JVM-虚拟机栈(局部变量表)

作者头像
utopia
发布2023-03-21 10:42:04
3100
发布2023-03-21 10:42:04
举报
文章被收录于专栏:UtopiaUtopia

1. 局部变量表

2.1 局部变量表介绍

  • 局部变量表:Local Variables,也被称之为局部变量数组或本地变量表
  • 定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference),以及 returnAddress(返回值) 类型。
  • 由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
  • 局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。
  • 方法嵌套调用的次数由栈的大小决定。一般来说,栈越大,方法嵌套调用次数越多。
    • 对一个函数而言,它的参数和局部变量越多,使得局部变量表膨胀,它的栈帧就越大,以满足方法调用所需传递的信息增大的需求。
    • 进而函数调用就会占用更多的栈空间,导致其嵌套调用次数就会减少。
  • 局部变量表中的变量只在当前方法调用中有效。
    • 在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。
    • 当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。

举例说明:局部变量表所需的容量大小是在编译期确定下来的

代码语言:javascript
复制
public class LocalVariablesTest {
    private int count = 0;

    public static void main(String[] args) {
        LocalVariablesTest test = new LocalVariablesTest();
        int num = 10;
        test.test1();
    }

    public void test1() {
        Date date = new Date();
        String name1 = "baidu.com";
        String info = test2(date, name1);
        System.out.println(date + name1);
    }

    public String test2(Date dateP, String name2) {
        dateP = null;
        name2 = "xiexu";
        double weight = 185.5;//占据两个slot
        char gender = '男';
        return dateP + name2;
    }

}

反编译后,可得结论:

  • 在编译期间,局部变量的个数、每个局部变量的大小都已经被记录下来
  • 所以局部变量表所需的容量大小是在编译期确定下来的

  • 利用 JClassLib 也可以查看局部变量的个数

代码语言:javascript
复制
JClassLib 参数详解

1.2 关于 Slot 的理解

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

代码语言:javascript
复制
在构造器以及实例方法中,对象引用this 都会存放在索引为0的位置
代码语言:javascript
复制
//构造器
public LocalVariablesTest() {
    this.count = 1;
}

//实例方法
public void test1() {
    Date date = new Date();
    String name1 = "baidu.com";
    test2(date, name1);
    System.out.println(date + name1);
}

代码语言:javascript
复制
64位的类型(long和double)占用两个slot
代码语言:javascript
复制
public String test2(Date dateP, String name2) {
        dateP = null;
        name2 = "xiexu";
        double weight = 185.5; //占据两个slot
        char gender = '男';
        return dateP + name2;
    }

可以看到,weight为double类型,索引从3直接跳到5,说明double占据两个slot

image.png
image.png
代码语言:javascript
复制
static方法无法调用this
代码语言:javascript
复制
public static void testStatic() {
        LocalVariablesTest test = new LocalVariablesTest();
        Date date = new Date();
        int count = 10;
        System.out.println(count);
        //因为this变量不存在于该静态方法的局部变量表中!!!
//        System.out.println(this.count);
    }

1.3 Slot 的重复利用

栈帧中的局部变量表中的槽位是可以重用的,如果一个局部变量出了其作用域,那么在其作用域之后声明新的局部变量就很有可能会复用过期局部变量的槽位,从而达到节省资源的目的。

代码语言:javascript
复制
public void test4() {
        int a = 0;
        {
            int b = 0;
            b = a + 1;
        }
        //变量c使用 之前已经销毁的变量b占据的slot的位置
        int c = a + 1;
    }
代码语言:javascript
复制
可以看到,局部变量c 重用了 局部变量b 的slot位置
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-09-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 局部变量表
    • 2.1 局部变量表介绍
      • 1.2 关于 Slot 的理解
        • 1.3 Slot 的重复利用
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档