1+2在JVM中的处理过程是什么样的?
接上几篇文章,我们了解了JVM运行时数据区域模型,JVM中的常用操作指令编码。下面我们来通过简单的例子a+b看看整个处理过程是怎么样的。
资料:
1、源码
public class AddDemo { public static void main(String[] args) { int a = 1; int b = 2; int c = add(a, b); System.out.println("c=" + c); } /*** * a+b * @param a * @param b * @return */ public static int add(int a, int b) { return a + b; } } 复制代码
2、Class文件
因为JVM能够读懂的是Java源码编译后的Class文件,所以我们要看Class文件。源码反编译后的文件如下:
Classfile /Users/zhangjian/works/workspace_home/docker-demo/target/classes/com/jianjang/docker/study/base/AddDemo.class Last modified 2022-10-22; size 987 bytes MD5 checksum 667fc2791a7668878bb530f04b32b4f2 Compiled from "AddDemo.java" public class com.jianjang.docker.study.base.AddDemo minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #12.#33 // java/lang/Object."<init>":()V #2 = Methodref #11.#34 // com/jianjang/docker/study/base/AddDemo.add:(II)I #3 = Fieldref #35.#36 // java/lang/System.out:Ljava/io/PrintStream; #4 = Class #37 // java/lang/StringBuilder #5 = Methodref #4.#33 // java/lang/StringBuilder."<init>":()V #6 = String #38 // c= #7 = Methodref #4.#39 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #8 = Methodref #4.#40 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; #9 = Methodref #4.#41 // java/lang/StringBuilder.toString:()Ljava/lang/String; #10 = Methodref #42.#43 // java/io/PrintStream.println:(Ljava/lang/String;)V #11 = Class #44 // com/jianjang/docker/study/base/AddDemo #12 = Class #45 // java/lang/Object #13 = Utf8 <init> #14 = Utf8 ()V #15 = Utf8 Code #16 = Utf8 LineNumberTable #17 = Utf8 LocalVariableTable #18 = Utf8 this #19 = Utf8 Lcom/jianjang/docker/study/base/AddDemo; #20 = Utf8 main #21 = Utf8 ([Ljava/lang/String;)V #22 = Utf8 args #23 = Utf8 [Ljava/lang/String; #24 = Utf8 a #25 = Utf8 I #26 = Utf8 b #27 = Utf8 c #28 = Utf8 MethodParameters #29 = Utf8 add #30 = Utf8 (II)I #31 = Utf8 SourceFile #32 = Utf8 AddDemo.java #33 = NameAndType #13:#14 // "<init>":()V #34 = NameAndType #29:#30 // add:(II)I #35 = Class #46 // java/lang/System #36 = NameAndType #47:#48 // out:Ljava/io/PrintStream; #37 = Utf8 java/lang/StringBuilder #38 = Utf8 c= #39 = NameAndType #49:#50 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #40 = NameAndType #49:#51 // append:(I)Ljava/lang/StringBuilder; #41 = NameAndType #52:#53 // toString:()Ljava/lang/String; #42 = Class #54 // java/io/PrintStream #43 = NameAndType #55:#56 // println:(Ljava/lang/String;)V #44 = Utf8 com/jianjang/docker/study/base/AddDemo #45 = Utf8 java/lang/Object #46 = Utf8 java/lang/System #47 = Utf8 out #48 = Utf8 Ljava/io/PrintStream; #49 = Utf8 append #50 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #51 = Utf8 (I)Ljava/lang/StringBuilder; #52 = Utf8 toString #53 = Utf8 ()Ljava/lang/String; #54 = Utf8 java/io/PrintStream #55 = Utf8 println #56 = Utf8 (Ljava/lang/String;)V { public com.jianjang.docker.study.base.AddDemo(); 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 11: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/jianjang/docker/study/base/AddDemo; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=4, args_size=1 0: iconst_1 1: istore_1 2: iconst_2 3: istore_2 4: iload_1 5: iload_2 6: invokestatic #2 // Method add:(II)I 9: istore_3 10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 13: new #4 // class java/lang/StringBuilder 16: dup 17: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 20: ldc #6 // String c= 22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 25: iload_3 26: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 29: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 32: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 35: return LineNumberTable: line 13: 0 line 14: 2 line 15: 4 line 16: 10 line 17: 35 LocalVariableTable: Start Length Slot Name Signature 0 36 0 args [Ljava/lang/String; 2 34 1 a I 4 32 2 b I 10 26 3 c I MethodParameters: Name Flags args public static int add(int, int); descriptor: (II)I flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=2 0: iload_0 1: iload_1 2: iadd 3: ireturn LineNumberTable: line 26: 0 LocalVariableTable: Start Length Slot Name Signature 0 4 0 a I 0 4 1 b I MethodParameters: Name Flags a b } SourceFile: "AddDemo.java" 复制代码
3、执行过程解读
关键字节码如下
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=4, args_size=1 0: iconst_1 //将常量1加载到操作数栈 1: istore_1 //将1从操作数栈存储到局部变量表 2: iconst_2 //将常量2加载到操作数栈 3: istore_2 //将2从操作数栈存储到局部变量表 4: iload_1 //将局部变量表的常量1压入操作数栈 5: iload_2 //将局部变量表的常量2压入操作数栈 6: invokestatic #2 // Method add:(II)I //执行add方法 9: istore_3 //将3从操作栈存储到局部变量表 //add方法 public static int add(int, int); descriptor: (II)I flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=2 0: iload_0 //将局部变量表的第1个常量压入操作数栈 1: iload_1 //将局部变量表的第2个常量压入操作数栈 2: iadd // 将最近的两个常量相加,并将结果压入操作数栈 3: ireturn //将结果压入调用方的栈顶(main方法栈顶) 复制代码
示意图1-main栈帧
网络异常,图片无法展示
|
示意图2-add栈帧
网络异常,图片无法展示
|
至此,整个操作过程解析结束。个人理解,有问题的话,感谢联系改正。谢谢。