JVM

JVM栈(stack)


定义

每个JVM线程拥有一个私有的 Java虚拟机栈,创建线程的同时栈也被创建。一个JVM栈由许多帧组成,称之为"栈帧"。JVM中的栈和C等常见语言中的栈比较类似,都用于保存局部变量和部分计算结果,同时也参与方法调用和返回。

对于栈来说不存在垃圾回收问题。只要线程一结束该栈则Over,生命周期和所在线程一致,是线程私有。

8中基本类型变量+对象的引用变量+实例方法都是在函数栈内存分配。

栈存储什么?

本地变量(Local Variables):输入参数和输出参数以及方法内的变量;

栈操作(Operand Stack):记录出栈,入栈的操作;

栈帧数据(Frame Data):包括类文件,方法等;

栈结构

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时数据区中的java虚拟机栈的栈元素。

栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。

局部变量表

1.局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。 并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。

2.局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)


 注意:

  很多人说:基本数据和对象引用存储在栈中。

  当然这种说法虽然是正确的,但是很不严谨,只能说这种说法针对的是局部变量。

  局部变量存储在局部变量表中,随着线程而生,线程而灭。并且线程间数据不共享。

  但是,如果是成员变量,或者定义在方法外对象的引用,它们存储在堆中。

  因为在堆中,是线程共享数据的,并且栈帧里的命名就已经清楚的划分了界限 : 局部变量表!


操作数栈

  • 与局部变量表一样,均以字长为单位的数组。不过局部变量表用的是索引,操作数栈是弹栈/压栈来访问。操作数栈可理解为java虚拟机栈中的一个用于计算的临时数据存储区。
  • 存储的数据与局部变量表一致含int、long、float、double、reference、returnType,操作数栈中byte、short、char压栈前(bipush)会被转为int。
  • 数据运算的地方,大多数指令都在操作数栈弹栈运算,然后结果压栈。
  • java虚拟机栈是方法调用和执行的空间,每个方法会封装成一个栈帧压入占中。其中里面的操作数栈用于进行运算,当前线程只有当前执行的方法才会在操作数栈中调用指令(可见java虚拟机栈的指令主要取于操作数栈)。
  • 如果int类型在-128~127(这个就直接存在常量池了)

动态连接

  每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,

  持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。

  在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析。

  另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接。

  这里简单提一下动态连接的概念,后面在详细讲解.

方法出口

  当一个方法开始执行后,只有2种方式可以退出这个方法 :

  方法返回指令 : 执行引擎遇到一个方法返回的字节码指令,这时候有可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口。

  异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出。

  无论采用任何退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息。

    一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中会保存这个计数器值。

  而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。

  • 作者:低调做个路人 (扫码联系作者)
  • 发表时间:2019-12-07 18:52:11
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 评论