JVM_栈

内存中的栈与堆

栈是运行时的单位,而堆是存储的单位

即∶栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。堆解决的 是数据存储的问题,即数据怎么放、放在哪儿。

栈中可能出现的异常

Java 虚拟机规范允许Java栈的大小是动态的或者是固定不变的。

>如果采用固定大小的Java虚拟机栈,那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过Java 虚拟机栈允许的最大容量,Java虚拟机将会抛出一个StackOverflowError 异常。

>如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法中请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,虚拟机将会抛出一个OpOfMempryError异常。

栈中存储什么?

每个线程都有自己的栈,栈中的数据都是以栈帧(stack Frame)的格式存在。

在这个线程上正在执行的每个方法都各自对应一个栈帧(Stack Frame)。

栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息。

栈运行原理

不同线程中所包含的栈帧是不允许存在相互引用的,即不可能在一个栈帧之中引用另外一个线程的栈帧。

如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回此方法的执行结果给前一个栈帧,接着,虚拟机会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧。

Java方法有两种返回函数的方式,一种是正常的函数返回,使用return指令;另外一种是抛出异常。不管使用哪种方式,都会导致栈帧被弹出。

 

 

 

局部变量表(local variables)

局部变量表也被称之为局部变量数组或本地变量表。

·定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型。

·由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题。

·局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。

举例∶静态变量与局邹变量的对比

   成员变量: 类变量:参数表分配完毕之后,再根据方法体内定义的变量的顺序和作用域分配。

            我们知道类变量表有两次初始化的机会,第一次是在"准备阶段",执行系统初始化,对类变量设置零值,另一次则是在"初始化"阶段,赋予程序员在代码中定义的初始值。

       实例变量:随着对象的创建,会在对空间中分配实例变量空间。并进行默认赋值

  局部变量:和类变量初始化不同的是,局部变量表不存在系统初始化的过程,这意味着一旦定义了局部变量则必须人为的初始化,否则无法使用。

public void test(){
      int i;
      System.out.println(i); 
}

这样的代码是错误的,没有赋值不能够使用。

操作数栈

· 操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。

· 操作数栈就是JVM执行引擎的一个工作区,当一个方法刚开始执行的时候,一个新的栈帧也会随之被创建出来,这个方法的操作数栈是空的。

·每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译期就定义好了,保存在方法的Code属性中,为max stack的值。

· 栈中的任何一个元素都是可以任意的Java数据类型。

  32bit的类型占用一个栈单位深度

  64bit的类型占用两个栈单位深度

·操作数栈并非采用访问索引的方式来进行数据访问的,而是只能通过标准的入栈(push)和出栈(pop)操作来完成一次数据访问。

posted @ 2020-08-03 17:14  Mistolte  阅读(170)  评论(0)    收藏  举报