JVM之一:操作数栈和局部变量表

每个方法被执行的时候,JVM 都会在虚拟机栈中创建一个栈帧栈帧是什么呢?

一、栈帧

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,每一个线程在执行某个方法时,都会为这个方法创建一个栈帧

我们可以这样理解:一个线程包含多个栈帧,而每个栈帧内部包含局部变量表操作数栈动态连接返回地址等。

这里来说下 局部变量表的最大长度操作数栈的最大深度

  1. 当一个方法开始执行的时候操作数栈是空的。
  2. 操作数栈的最大深度在编译期就决定了。
  3. 栈中的任何一个元素可以是任意的Java 类型

注意
32 bit 占一个单位深度(slot)
64 bit 占2个单位深度(slot) 即 long double 类型占2个slot

下面举例说明:

     public void add(int a, int b) {
          int sum = a + b;
      }

操作指令如下:

public void add(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: istore_3
         4: return
      LineNumberTable:
        line 6: 0
        line 7: 4

解释下上面的语句。
当add方法编译开始的时候:局部变量表里面的元素是 [this, int, int] 。因为add方法是普通方法而不是 static 方法,所以索引为0的位置存放的是当前类的对象;
静态方法属于类而不是对象,所以不需要。

iload_1 :把局部变量表索引为1的(参数a的值)压入栈:[int] — int 型数据所以用 iload,如果是对象的引用则用 aload
iload_2 :把局部变量表索引为2的(参数b的值)压入栈:[int, int]
iadd :把栈上的最上面2个数据先出栈,然后相加,得到的结果再次压入栈:[int] 存的是相加的结果
istore_3 :把栈顶的数据放到局部变量表索引为3的位置 [this, int, int,int]
return : 方法执行完,退出

如上,可以看到 栈的最大深度为2,局部变量表的最大长度为4,符合上面的 stack=2, locals=4。

当我们把 add 方法参数类型改为 long ,如下:

public void add(long a, long b) {
    long sum = a + b;
}

如下:

public void add(long, long);
    descriptor: (JJ)V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=7, args_size=3
         0: lload_1
         1: lload_3
         2: ladd
         3: lstore        5
         5: return
      LineNumberTable:
        line 6: 0
        line 7: 5

为是 long 类型,占2个slot,所以开始的局部变量表如下:[this, long, top, long, top]
lload_1 : 操作栈 [long, top]
lload_3 : 操作栈 [long, top, long, top]
ladd : 出栈后相加后压入栈 [long, top]
lstore : 将栈顶的求和的结果存入局部变量表:[this, long, top, long, top, long, top]

所以 栈最大深度为4,局部变量表的最大长度为 7,符合上面的 stack=4, locals=7

二、如果方法有返回值的话,其返回值将会被压入当前栈帧的操作数栈中。

public int add(int a, int b) {
    int sum = a + b;
    return sum;
}
public int add(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: istore_3
         4: iload_3 // 多了一步将局部变量表索引值为3的数组压入操作数栈
         5: ireturn // 因为这次 add 有返回值,且返回值为 int 类型,所以指令为 ireturn
      LineNumberTable:
        line 6: 0
        line 7: 4
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值