美文网首页
关于Java虚拟机(JVM)栈操作的理解

关于Java虚拟机(JVM)栈操作的理解

作者: zhd______ | 来源:发表于2020-07-22 11:59 被阅读0次

首先新建一个Hello.java文件,文件代码如下:

public class Hello{
    public int foo(int a,int b){
        return (a+b)*(a-b);
    }
    
    public static void main(String[] args){
        Hello hello = new Hello();
        System.out.println(hello.foo(5,3));
    }
}

1、将Hello.java 编译成Hello.class,输入命令

javac Hello.java

2、使用javap命令反编译Hello.class查看foo()函数的java字节码

javap -c -classpath . Hello

输出结果

Compiled from "Hello.java"
public class Hello {
  public Hello();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int foo(int, int);
    Code:
       0: iload_1
       1: iload_2
       2: iadd
       3: iload_1
       4: iload_2
       5: isub
       6: imul
       7: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class Hello
       3: dup
       4: invokespecial #9                  // Method "<init>":()V
       7: astore_1
       8: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_1
      12: iconst_5
      13: iconst_3
      14: invokevirtual #16                 // Method foo:(II)I
      17: invokevirtual #20                 // Method java/io/PrintStream.println:(I)V
      20: return
}

查看foo()方法发现一共占用了8个字节,并且这些指令都没有参数。
指令iload_1 可以分成3个部分,i表示int,load表示将局部变量压栈。
下划线右边的数字代表取第几个局部变量,下标从0开始。

结合以上我们发现foo()函数前两条指令分别为iload_1,iload_2,这和下标从0开始好像有冲突,按照理解前两条指令应该是iload_0,iload_1。笔者带着这个疑问习惯性的先去问度娘,最终没有找到想要的答案。

和同事讨论了一番之后觉得可能是对象的原因,接着试着将foo()方法改为static,再次编译看看结果

 public static int foo(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: iadd
       3: iload_0
       4: iload_1
       5: isub
       6: imul
       7: ireturn

可以看到原本的iload_1变成了iload_0,为什么会这样呢 ,我们接着将static去掉然后打印this再次编译

 public int foo(int, int);
    Code:
       0: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       7: iload_1
       8: iload_2
       9: iadd
      10: iload_1
      11: iload_2
      12: isub
      13: imul
      14: ireturn

我们看到第二行指令有个aload_0(从局部变量中装载引用类型值),
从指令上看对象方法的第一个局部变量为this,这里就很好的解释了为什么会从索引为1开始了。

上面的疑问基本解决了,我们再解释下foo()方法中指令的意思,我们用以下指令来讲解

public int foo(int, int);
    Code:
       0: iload_1
       1: iload_2
       2: iadd
       3: iload_1
       4: iload_2
       5: isub
       6: imul
       7: ireturn

指令1:将第一个参数的int类型的局部变量进行压栈
指令2:将第二个参数的int类型的局部变量进行压栈
指令3:从栈顶弹出两个int类型的变量做加法再将结果(标记为R1)压栈
这个时候栈里应该只有R1

指令4:将第一个参数的int类型的局部变量进行压栈
指令5:将第二个参数的int类型的局部变量进行压栈
指令6:从栈顶弹出两个int类型的变量做减法再将结果(标记为R2)压栈
这时候栈里应该就有R1和R2

指令7:从栈里弹出R1和R2做乘法并将结果压栈
指令8:进行int数据返回

到这里也就全部分析完了

相关文章

  • 深入理解java虚拟机之jvm内存模型

    深入理解JVM—JVM内存模型 java的内存模型包括:本地方法区,java堆,Java虚拟机栈,本地方法栈,程序...

  • 解答JVM、JDK、JRE是什么?

    JVM理解 JVM全称就叫java虚拟机是运行java字节码的一个东西(虚拟机),JVM针对不同的操作系统会有不用...

  • JVM 运行时数据区

    引自《深入理解Java 虚拟机》 前言 JVM 运行时数据分为几大部分 程序计数器 Java 虚拟机栈 本地方法栈...

  • 插件化,热修复基础之虚拟机

    java虚拟机 jvm jvm整体结构 jvm内存空间 java 栈区 它存放的是java方法执行时的所有的数据栈...

  • JVM栈以及其对线程并发量的影响

    JVM栈 ​根据JVM规范,JVM包括两种栈,java虚拟机栈和本地方法栈。也就是说,每当启动一个java线程时,...

  • 2021-01-19 线程运行原理

    栈与栈帧 Java Virtual Machine Stacks (Java 虚拟机栈)我们都知道 JVM 中由堆...

  • Java常见面试题汇总-----------JVM专题(JVM内

    29、JVM内存模型(区别Java内存模型)   JVM内存主要分为:程序计数器,Java虚拟机栈,本地方法栈,J...

  • 深入探究JVM

    1、JVM 请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新? 什么是OOM,什么是栈溢出StackOv...

  • E.JVM

    1、JVM定义 Java虚拟机包括程序计数器(线程私有),虚拟机栈(线程私有),本地方法栈(线程私有),Java堆...

  • 第46节:Java当中的常量池

    Java当中的常量池 在Java虚拟机jvm中,内存分布为:虚拟机堆,程序计数器,本地方法栈,虚拟机栈,方法区。 ...

网友评论

      本文标题:关于Java虚拟机(JVM)栈操作的理解

      本文链接:https://www.haomeiwen.com/subject/iryclktx.html