JVM之栈详解

一.栈的概念

  • 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
  • 主管程序运行,生命周期和线程同步,线程结束,栈内存就释放了。不存在垃圾回收问题
  •  JVM 栈描述的是每个线程 Java 方法执行的内存模型:每个方法被执行的时候,JVM 会同步创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口 等信息。

  • 栈是运行时单位,而堆是存储的单位,即栈解决的是运行问题,即程序如何执行,或者如何处理数据,功能类似于计算机硬件 PC寄存器。堆解决的是数据存储的问题,即数据怎么放、放哪儿。

特点

  • 访问速度快,仅次于程序计数器
  • 线程私有
  • 存在 OOM,不存在 GC

存放的类型8种数据类型、对象的引用、实例的方法
栈模型

  1.  Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)
  2.  如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)
  3. Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。对于我们来说,主要关注的stack栈内存,就是虚拟机栈中局部变量表部分

二.栈和队列

  • 栈:先进后出,后进先出
  • 队列:先进先出(FIFO)

三.栈帧

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

①栈帧位置

在这里插入图片描述

②栈帧内存

一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

③栈帧结构

局部变量表(Local Variable Table)

  • 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。
  • 局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)

  注意:

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

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

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

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

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

变量槽(Variable Slot)

  • 局部变量表的容量以变量槽为最小单位,每个变量槽都可以存储32位长度的内存空间,例如boolean、byte、char、short、int、float、reference。
  • 对于64位长度的数据类型(long,double),虚拟机会以高位对齐方式为其分配两个连续的Slot空间,也就是相当于把一次long和double数据类型读写分割成为两次32位读写。

 操作数栈(Operand Stack)

同样也可以在编译期确定大小。
Frame 被创建时,操作栈是空的。操作栈的每个项可以存放 JVM 的各种类型数据,其中 long 和 double 类型(64位数据)占用两个栈深。
方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈和入栈操作(与 Java 栈中栈帧操作类似)。操作栈调用其它有返回结果的方法时,会把结果 push 到栈上(通过操作数栈来进行参数传递)。

动态链接(Dynamic Linking)

  •  每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,
  •  持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。
  •  在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析。
  •  另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接。

 

返回地址(Return Address)

方法开始执行后,只有 2 种方式可以退出 :方法返回指令,异常退出。

帧数据区(Stack Data)


四.栈的两类异常 

  • 如果虚拟机栈容量不可以动态扩展,当线程请求的栈深度大于虚拟机允许的最大容量,就会抛出 StackOverFlowError 异常;

  • 如果虚拟机栈容量可以动态扩展,当栈无法申请到足够的内存会抛出 OutOfMemoryError 异常。

    HotSpot 虚拟机不支持动态扩展,所以只有在创建线程申请内存时因为无法获得足够的内存才会导致 OutOfMemoryError 异常。

参考:https://blog.csdn.net/gtaaaa/article/details/105663199?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160648706119721940292258%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160648706119721940292258&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-105663199.pc_first_rank_v2_rank_v28p&utm_term=JVM%E6%A0%88

参考:https://www.cnblogs.com/newAndHui/p/11168791.html 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值