Java方法在栈帧中的执行过程

Java方法的字节码结构

以如下代码为例,对 Java 方法的字节码结构进行阐述(jdk 版本 1.8.0_301)。

package com.zero.demo;

public class MethodAnalyzeDemo {

    public int doSomething(int i, int j) {
        int result = i + j;
        return result;
    }
}

通过 javac 命令,可以对 .java 文件进行编译,将源代码编译成字节码,即生成 .class 文件。

javac MethodAnalyzeDemo.java

通过 javap -verbose 命令,将会根据 .class 文件的字节码,打印出 Java 类中方法的字节码信息。


PS C:\Users\Zero\Desktop\demo> javap -verbose .\MethodAnalyzeDemo.class
Classfile /C:/Users/Zero/Desktop/demo/MethodAnalyzeDemo.class
  Last modified 2021-12-26; size 292 bytes
  MD5 checksum ee74d225ac594d1577a0005f2106072d
  Compiled from "MethodAnalyzeDemo.java"
public class com.zero.demo.MethodAnalyzeDemo
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#12         // java/lang/Object."<init>":()V
   #2 = Class              #13            // com/zero/demo/MethodAnalyzeDemo
   #3 = Class              #14            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               doSomething
   #9 = Utf8               (II)I
  #10 = Utf8               SourceFile
  #11 = Utf8               MethodAnalyzeDemo.java
  #12 = NameAndType        #4:#5          // "<init>":()V
  #13 = Utf8               com/zero/demo/MethodAnalyzeDemo
  #14 = Utf8               java/lang/Object
{
  public com.zero.demo.MethodAnalyzeDemo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public int doSomething(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
         5: ireturn
      LineNumberTable:
        line 6: 0
        line 7: 4
}
SourceFile: "MethodAnalyzeDemo.java"

其中,关于 doSomething() 方法的字节码信息,如下图所示:

图1
图1

在 JVM 中,一个线程为一个栈,一个栈由多个栈桢组成,一个栈桢对应一个方法。

因此,doSomething() 方法在栈帧中的结构,如下图所示:

图2
图2

接下来,对 doSomething() 方法的每个部分进行讲述。

descriptor: (II)I

descriptor: (II)I

descriptor 表示方法的描述,(II) 表示 doSomething() 方法有两个 int 类型的形参,I 表示方法的返回值是 int 类型。

flags: ACC_PUBLIC

flags: ACC_PUBLIC

flags 表示方法的访问标志,ACC_PUBLIC 表示 doSomething() 方法的访问标志为 public。

Code

Code:
  stack=2, locals=4, args_size=3
     0: iload_1
     1: iload_2
     2: iadd
     3: istore_3
     4: iload_3
     5: ireturn
  LineNumberTable:
    line 6: 0
    line 7: 4

Code 是方法表,表示 Java 方法经过编译后的字节码指令,就是以字节码的形式表达 Java 方法的执行过程。

stack=2, locals=4, args_size=3

表示方法在栈帧的基本信息,具体说明如下所示。

  • stack

操作数栈的深度

  • locals

局部变量表的大小

  • args_size

方法形参的数量,例如 doSomething() 方法的 args_size:

args_size = 3 = int i + int j + 对象实例的引用

对象实例的引用,可以理解为,通过 this 关键字访问此方法所属的对象。

举个例子,我们日常开发中经常使用到的 this.i = i;

public class Demo {
    int i;
    public setI(int i) {
        this.i = i;
    }
}

0: iload_1 …… 5: ireturn

表示方法执行的指令,就是 int result = i + j; 和 return result; 这两行代码对应的指令。

  • 0: iload_1

将局部变量表中第二个变量(i)加载到操作数栈,这个变量是 int 类型。

  • 1: iload_2

将局部变量表中第三个变量(j)加载到操作数栈,这个变量是 int 类型。

  • 2: iadd

将操作数栈中栈顶的两个 int 类型变量(i,j)出栈,把它们相加的结果加载到栈顶(i + j)。

  • 3: istore_3

将操作数栈中栈顶的 int 类型变量(就是 iadd 的结果)进行出栈,并且赋值局部变量表的第四个变量(result)。

  • 4: iload_3

将局部变量表中第四个变量(result)加载到操作数栈,这个变量是 int 类型。

  • 5: ireturn

将操作数栈中栈顶的 int 类型变量(result)返回。

0: iload_1 …… 5: ireturn 的执行过程,如下图所示:

图3
图3

为什么没有 iload_0 ?

因为,构造方法或实例方法(非静态方法),对象实例的引用(this)会存放在索引为 0 的位置,其余参数按照参数表顺序进行排列。

而且,如果方法修改为如下所示,那么 0: iload_1 就会变成 0: iload_2,因为 String str 位于局部变量表索引为 1 的位置,int i 位于局部变量表索引为 2 的位置。


LineNumberTable

表示 java 源代码(.java文件)的行号和字节码(.class文件)的行号之间的对应关系,主要是方便在异常发生的时候,在堆栈中显示出源代码出错的行号;以及在调试过程中,按照源代码的行号设置断点。

LineNumberTable 不是运行时必需的属性,通过 -g:none 参数取消,-g:lines 参数生成(默认)。

line 6: 0、line 7: 4 的含义,如下图所示:

图4
图4
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值