JVM--虚拟机栈

虚拟机栈概念

目录

虚拟机栈概念

栈帧

代码演示


  1. 虚拟机栈是线程独占区域,就是每个线程都拥有自己的虚拟机栈内存

  2. 为虚拟机执行Java方法服务,储存运行时的数据信息,由Java代码写的方法

  3. 虚拟机栈由栈帧组成,一个方法构成一个栈帧

  4. 栈帧由局部变量表、操作数栈、动态链接、返回地址组成,还有一些其它无关的数据

  5. 每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程

如下图(局部变量表中第0位索引的Slot默认是用于传递方法所属对象实例的引用,this,如果是静态方法就没有this)

 

栈帧

虚拟机栈就是由一个一个栈帧组成,一个方法就是一个栈帧,栈帧又由局部变量表、操作数栈、动态链接、返回地址构成(其它不重要的信息忽略),每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程

1、局部变量表

方法内部定义的变量,都由栈帧的局部变量表记录保存,直到方法结束,栈帧释放时局部变量表也会释放,通过索引来访问(静态方法下标0记录的还是正常的参数,因为它属于类,普通方法下标0记录的是对象的实例引用this)

2、操作数栈

方法内部需要进行的逻辑运算的数据都由操作数栈来存放(大致操作:从局部变量表取出到操作数栈中,然后从操作数栈取出进行运算,将运算结果压入操作数栈顶,最终出栈并将运算结果存储到局部变量表),操作执行,通过压栈和出栈来访问

3、动态链接

多态时确定具体类型

符号引用就相当于名字,这些被调用者的名字就存放在Java字节码文件里(.class 文件),名字是知道了,但是Java真正运行起来的时候,如何靠这个名字(符号引用)找到相应的类和方法,需要解析成相应的直接引用,利用直接引用来准确地找到相应的类和方法

4、返回地址

记录的是返回代码的位置,找到位置,继续执行代码

引用专业比较的话:

当一个方法开始执行后,只有两种方式可以退出,一种是遇到方法返回的字节码指令;一种是遇见异常,并且这个异常没有在方法体内得到处理

无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息

方法退出的过程实际上就等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令等

 

代码演示

1、代码

 

分析,方法两个,main test,main方法局部变量表最终两个参数parm,res,test局部变量表两个参数i,parm

用命令行的命令对class文件进返编译,javap -c Test5,如下,已经附上解释

Compiled from "Test5.java"
public class Test5 {
  public Test5();//默认构造方法
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
//main方法的栈帧
  public static void main(java.lang.String[]);//主函数 参数args入栈顶,出栈存入局部变量表下标为0的地方
    Code:
       0: iconst_4							//1、变量int值4压入操作数栈顶
       1: istore_1							//2、4从栈顶弹出,存入局部变量表下标为1的地方
       2: iload_1							//3、取局部变量表下标为1的值,就是取parm=4
       3: invokestatic  #2                  //4、Method test:(I)I调用静态方法,并且传值4进入test方法
       6: istore_2							//13、将返回值存入局部变量表下标为2的地方
       7: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: iload_2							//14、取出局部变量表下标为2的变量res,压栈
      11: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
      14: return
//test方法的栈帧 静态方法-局部变量表0的位置有方法参数存方法参数,无方法参数存局部变量  普通方法-局部变量表0的位置存的是this,指的是实例的引用
//首先局部变量表中第0位索引的Slot默认是用于传递方法所属对象实例的引用
  public static int test(int);//参数压入栈顶,出栈,存入局部变量表下标0的位置
    Code:
       0: iconst_1							//5、变量int值1压入操作数栈顶
       1: istore_1							//6、1从栈顶弹出,存入局部变量表下标为1的地方
       2: iload_1							//7、取局部变量表下标为1的值,就是取i=1压入操作数栈顶
       3: iload_0							//8、取局部变量表下标为0的值,就是取方法参数parm=4压入操作数栈顶,此时操作数栈有4、1
       4: iadd								//9、从操作数栈中弹出两个int值进行相加操作,相加的结果5压栈
       5: istore_1							//10、5从栈顶弹出,存入局部变量表1的地方
       6: iload_1							//11、取局部变量表下标为1的值,就是取i=5压操作数栈
       7: ireturn							//12、5出栈,返回到上面
}

 

2、代码----i++ ++i解释

public class Test5 {
	public static void main(String[] args) {
		int i = 1;
		i = i++;
		i = ++i;
	}
}

反编译字节码及其解释

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

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1							//int值1进操作数栈顶
       1: istore_1							//值1出操作数栈,存入局部变量表下标为1处
       //i = i++
       2: iload_1							//取局部变量表下标1的值1压入操作数栈中
       3: iinc          1, 1				//局部变量表的值+1 就是为2
       6: istore_1							//值1出操作数栈,存入局部变量表下标为1处,局部变量表又变成1
       //i = ++i
       7: iinc          1, 1				//局部变量表的值+1 就是为2
      10: iload_1							//取局部变量表下标1的值2压入操作数栈中
      11: istore_1							//值2出操作数栈,存入局部变量表下标为1处,局部变量表还是2
      12: return
}

 

3、代码----对于i++ ++i参与运算

public class Test5 {
	public static void main(String[] args) {
		int i= 1;
		i = i++ + 3;
		i = ++i + 3;
	}
}

反编译字节码及其解释

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

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1							//int 1压入操作数栈顶
       1: istore_1							//值1 操作数栈顶出栈,存入局部变量表下标为1处
       //i = i++ + 3;
       2: iload_1							//从局部变量表下标1处取值1,压入操作数栈顶
       3: iinc          1, 1				//局部变量表下标1处 +1 此时为2
       6: iconst_3							//int 3 压入操作数栈顶
       7: iadd								//出栈 相加 3+1=4,4入操作数栈顶 
       8: istore_1							//出栈,存入局部变量表下标为1处
       //i = ++i + 3;
       9: iinc          1, 1				//局部变量表下标1处 +1 此时为2
      12: iload_1							//取局部变量表下标1处的值压入操作数栈顶
      13: iconst_3							//3 压入操作数栈顶
      14: iadd								//3出栈,2出栈 3+2=5,5入操作数栈
      15: istore_1							//5出栈,存入局部变量表下标1处
      16: return							//结束,释放栈帧内存
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值