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

Posted 小猪快跑22

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于JVM之一:操作数栈和局部变量表的主要内容,如果未能解决你的问题,请参考以下文章

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

JVM指令手册

Jvm(61),虚拟机字节码执行引擎----操作数栈

JVM的基本结构及其各部分详解

JVM常见面试题

jvm内存区域之虚拟机栈