版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36367789/article/details/81711223

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素。栈帧存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息。第一个方法从调用开始到执行完成,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

每一个栈帧都包括了局部变量表操作数栈动态连接方法返回地址一些额外的附加信息。在编译代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到了方法表的Code属性中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体虚拟机的实现

一个线程中的方法调用链可能会很长,很多方法都同时处理执行状态。对于执行引擎来讲,活动线程中,只有虚拟机栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),这个栈帧所关联的方法称为当前方法(Current Method)。执行引用所运行的所有字节码指令都只针对当前栈帧进行操作。栈帧的概念结构如下图所示:

1. 局部变量表

局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在编译Class文件时,就在方法的Code属性的max_locals数据项中已经确定了该方法需要分配的局部变量表的最大容量。

变量槽 (Variable Slot)是局部变量表的最小单位,没有强制规定大小为 32 位,虽然32位足够存放大部分类型的数据。一个 Slot可以存放 booleanbytecharshortintfloatreferencereturnAddress 8种类型。其中 reference 表示对一个对象实例的引用,通过它可以得到对象在Java 堆中存放的起始地址的索引和该数据所属数据类型在方法区的类型信息。returnAddress则指向了一条字节码指令的地址。 对于64位的 long 和 double 变量而言,虚拟机会为其分配两个连续的 Slot 空间

虚拟机通过索引定位的方式使用局部变量表。之前我们知道,局部变量表存放的是方法参数和局部变量。当调用方法是非static 方法时,局部变量表中第0位索引的 Slot 默认是用于传递方法所属对象实例的引用,即 “this” 关键字指向的对象。分配完方法参数后,便会依次分配方法内部定义的局部变量。

Slot复用验证

为了节省栈帧空间,局部变量表中的 Slot 是可以重用的。当离开了某些变量的作用域之后,这些变量对应的 Slot 就可以交给其他变量使用。这种机制有时候会影响垃圾回收行为。

public class Main {public static void main(String[] args) {byte[] placeholder = new byte[64*1024*1024];System.gc();}
}
[GC (System.gc())  69468K->66384K(188416K), 0.0016481 secs]
[Full GC (System.gc())  66384K->66280K(188416K), 0.0079337 secs]
public class Main {public static void main(String[] args) {{byte[] placeholder = new byte[64*1024*1024];}int a = 0;System.gc();}
}
[GC (System.gc())  69468K->66368K(188416K), 0.0012876 secs]
[Full GC (System.gc())  66368K->744K(188416K), 0.0055897 secs]

可以看到,当我吧byte的声明单独放到代码块中,然后再执行作用域之外的代码的时候,gc对slot进行了回收。

注意:jvm不会给局部变量赋初始值,只给全局变量赋初始值。

2. 操作数栈

操作数栈(Operand Stack)也常称为操作栈,是一个后入先出栈。在Class 文件的Code 属性的 max_stacks 指定了执行过程中最大的栈深度。Java 虚拟机的解释执行引擎称为”基于栈的执行引擎“,这里的栈就是指操作数栈。

方法执行中进行算术运算或者是调用其他的方法进行参数传递的时候是通过操作数栈进行的。

jvm对操作数栈的优化

在概念模型中,两个栈帧是相互独立的。但是大多数虚拟机的实现都会进行优化,令两个栈帧出现一部分重叠。令下面的部分操作数栈与上面的局部变量表重叠在一块,这样在方法调用的时候可以共用一部分数据,无需进行额外的参数复制传递

3. 动态链接

每个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。

Class 文件中存放了大量的符号引用,字节码中的方法调用指令就是以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析。另一部分将在每一次运行期间转化为直接引用,这部分称为动态连接

4. 方法返回地址

当一个方法开始执行以后,只有两种方法可以退出当前方法

  1. 当执行遇到返回指令,会将返回值传递给上层的方法调用者,这种退出的方式称为正常完成出口(Normal Method Invocation Completion),一般来说,调用者的PC计数器可以作为返回地址
  2. 当执行遇到异常,并且当前方法体内没有得到处理,就会导致方法退出,此时是没有返回值的,称为异常完成出口(Abrupt Method Invocation Completion),返回地址要通过异常处理器表来确定

当方法返回时,可能进行3个操作

  1. 恢复上层方法的局部变量表和操作数栈
  2. 把返回值压入调用者调用者栈帧的操作数栈
  3. 调整 PC 计数器的值以指向方法调用指令后面的一条指令

5. 附加信息

虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧之中,例如与调试相关的信息,这部分信息完全取决于具体的虚拟机实现。在实际开发中,一般会把动态连接、方法返回地址与其他附加信息全部归为一类,称为栈帧信息。

JVM运行时栈帧结构相关推荐

  1. JVM -- 运行时栈帧结构简介

    栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...

  2. JVM007_运行时栈帧结构

    运行时栈帧结构 执行引擎是JVM的核心组件之一. 所有Java虚拟机的执行引擎输入输出都是一致的:输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果. JVM以方法作为作基本 ...

  3. Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)

    Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...

  4. java帧结构_Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)...

    Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...

  5. java虚拟机栈帧_Java虚拟机,运行时栈帧结构

    业余生活要有意义,不要越轨.--华盛顿 引导语 "虚拟机"是一个相对于"物理机"的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器. ...

  6. JVM内存模型:运行时栈帧结构

    栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...

  7. 运行时栈帧结构是怎样的?

    写在前面 本文隶属于专栏<100个问题搞定Java虚拟机>,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java ...

  8. 深入理解Java虚拟机——运行时栈帧结构(局部变量表)

    目录 一.局部变量表的概述 二.reference类型的概述 三.renturnAddress类型的概述 四.局部变量表中Slot槽复用对垃圾回收的影响 4.1.局部变量表中Slot槽复用对垃圾回收的 ...

  9. JVM运行时的内存结构

    我们都知道,JVM的垃圾收集机制能够帮开发者自动管理内存,了解JVM运行时的内存结构是理解垃圾收集机制的前提.本文主要简单介绍JVM运行时的内存结构. [JVM运行时内存中不同的数据区域] 一.PC寄 ...

最新文章

  1. 球面贴图,立方体贴图的比较
  2. 清华学姐的研究生复试经验!
  3. Java 虚拟机总结给面试的你(中)
  4. Kubernetes v1.17 版本解读 | 云原生生态周报 Vol. 31
  5. 查找有权限使用某个T-Code的所有用户列表
  6. php文件夹0777,PHP代码mkdir(‘images’,’0777′)创建一个具有411权限的文件夹!为什么?...
  7. RedHat Enterprise Linux Server 5 在VMware Workstation 6.5的详细安装过程(2)
  8. Ubuntu gedit中文乱码-转
  9. DirectX9:总结篇 异常错误检测
  10. Unity工程中 .Meta 文件的来龙去脉
  11. 面试题(4)--基础篇
  12. c语言超市,C语言超市收银系统
  13. Mysql修改数据库名
  14. Android 12上焕然一新的小组件:美观、便捷和实用
  15. Web全栈~06.CSS选择器
  16. mfc实现c语言的注释,C语言学习:标识符、关键字、注释、表达式和语句
  17. 卡夫卡详解_卡夫卡概念
  18. mysql清除表数据
  19. 那些年UNIX教我们的事
  20. STM32智能门锁学习一,按键解锁,蓝牙解锁、oled显示,步进电机

热门文章

  1. shell实例第7讲:awk命令
  2. 什么事孤儿进程和僵死进程?
  3. STM32 USART串口DMA 接收和发送的源码详解!
  4. 6.STM32外设函数分类
  5. spring10: 引用类型的自动注入
  6. Logtail提升采集性能
  7. 如何快速学好Shell脚本?
  8. AngularJS的稍复杂form验证
  9. Linux磁盘管理----分区格式化挂载fdisk、mkfs、mount
  10. Mysql忘记用户密码的解决办法