Java运行时栈帧结构

摘要:
Java运行时堆栈框架结构Java虚拟机使用方法作为最基本的执行单元。“堆栈框架”是支持虚拟机的方法调用和方法执行背后的数据结构。它也是虚拟机运行时数据区域中虚拟机堆栈的堆栈元素。堆栈帧存储本地变量表、操作数堆栈、动态连接、方法返回地址和方法的一些附加信息。从Java程序的角度来看,调用堆栈中的所有方法都同时在同一线程中执行。当Java程序编译为类文件时。
Java运行时栈帧结构

Java虚拟机以方法作为最基本的执行单元,“栈帧”则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈的栈元素,栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址和一些额外的附加信息。在编译Java程序源码的时候,栈帧中需要多大的局部变量表,需要多深的操作数栈就已经被分析计算出来了,并且写到方法表的code属性中。换言之,一个栈帧需要分配多少内存,并不会受到运行时变量的数据的影响,仅仅取决于程序源码和具体的虚拟机实现的栈内存布局形式。

以Java程序的角度来看,同一时刻、同一条线程里面,在调用堆栈的所有方法都同时处于执行状态。而对于执行引擎来讲,在活动线程里面,只有位于栈顶的方法才是运行的,只有位于栈顶的栈帧才是生效的,其被称为“当前栈帧”,与这个栈帧所关联的方法称为“当前方法”。

Java运行时栈帧结构第1张

一、局部变量表

局部变量表是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译为class文件时。就在方法的code属性的max_locals数据项中确定了该方法所需分配的局部变量表的最大容量。Java虚拟机规范没有明确指出一个变量槽的大小,但是每个变量槽都应该能存放一个Boolean、byte、char、short、int、float、reference或returnAddress类型的数据,这8种数据类型,都可以使用32位或更小的物理内存来存储。对于64位的数据类型,Java虚拟机会以高位对齐的方式为其分配俩个连续的变量槽空间,Java语言中明确64位的数据类型只有long和double俩种。

Java虚拟机通过索引定位的方式使用局部变量表,索引值的范围时从0开始至局部变量表最大的变量槽数。如果访问的是32位数据类型的变量,索引N就代表了使用第N个变量槽,如果访问的是64位数据类型的变量,则说明会同时使用第N和N+1俩个变量槽。

当一个方法被调用,Java虚拟机会使用局部变量表完成参数值到参数变量列表的传递过程,如果执行的是实例方法,那局部变量表中第0位索引的变量槽默认是实例引用(可通过this使用),其余参数按照参数表顺序排列。为了尽可能节省栈帧耗用的内存空间,局部变量表的变量槽是可以复用的。

二、操作数栈

操作数栈也常被称为操作栈,它是一个后入先出栈。同局部变量表一样,操作数栈的最大深度也在编译阶段被写入到code属性的max_stacks数据项中。32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2。

当一个方法体刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,就是出栈和入栈的操作。在概念模型中,俩个不同的栈帧作为不同方法的虚拟机栈的元素,是完成相互独立的。但是在大多的虚拟机栈中会进行一些优化处理,令俩个栈帧出现一部分重叠。

Java运行时栈帧结构第2张 

三、动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。calss文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数,这些符号引用会在类加载阶段或者第一次使用的时候转化为直接引用,这个转化称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分就称为动态连接。

四、方法返回地址

当一个方法开始执行后,只有俩种方式退出这个方法。第一种方式是执行引擎遇到任意一个方法返回字节码指令,这个时候可能会有返回值传递给上层的方法调用者,这个方法是否有返回值以及返回值的类型将根据遇到何种方法返回指令来决定,这种退出方法的方式称为“正常调用完成”

另一种退出方式是在方法执行中遇到了异常,并且这个异常没有在方法体中得到妥善的处理,无论以何种方式产生异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出。这种退出方法的方式称为“异常调用完成”。此时是不会给它的上层调用者提供任何返回值的。

在方法退出后,都必须返回到最初方法被调用时的位置,程序才能继续执行。一般来说,方法正常退出,主调方法的pc计数器就可以作为返回地址,栈帧中很可能会保存这个计数器的值。方法异常退出时,返回地址是通过异常处理表来确定的。

五、附件信息

这里的附加信息是Java虚拟机规范虚拟机实现可以增加一些其他信息到栈帧中,例如与调试、性能收集相关的信息,这部分信息完全取决于具体的虚拟机实现,一般会把动态连接、方法返回地址与附加信息全部归为一类,称为栈帧信息。

参考:

《深入理解Java虚拟机》周志明

免责声明:文章转载自《Java运行时栈帧结构》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇FPGA中实现三态缓冲器spring5 源码深度解析----- AOP代理的生成下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python3+Scrapy爬虫使用pipeline数据保存到文本和数据库,数据少或者数据重复问题

爬取的数据结果是没有错的,但是在保存数据的时候出错了,出现重复数据或者数据少问题。那为什么会造成这种结果呢? 其原因是由于Spider的速率比较快,而scapy操作数据库操作比较慢,导致pipeline中的方法调用较慢,这样当一个变量正在处理的时候,一个新的变量过来,之前的变量的值就会被覆盖。 就比如pipline的速率是1TPS,而spider的速率是5...

Ubuntu ftp服务器搭建 + UltraEdit编辑FTP文件

0. 前言:(请无视) 最近在写一个Linux脚本,在电脑装了Ubuntu的虚拟机来测试脚本效果;可是用vim编辑脚本实在是太蛋疼,于是就想到UltraEdit编写,然后通过ftp上传到Ubuntu虚拟机中...... 一、Ubuntu 搭建ftp 服务器 1. vsftpd 服务安装 在虚拟机能联网的情况下很简单,就一条命令,然后等结果就好了,没联网我也...

8086汇编语言(1)虚拟机安装ms-dos 7.1

8086汇编语言(1)虚拟机安装ms-dos 7.1 文/玄魂 前言 在开始这一系列文章之前,我想先说下,对于古董级的8086汇编到底还以有没有学习的必要。这里我说下我要从8086开始学习,而不是从win32汇编或者win64汇编直接开始学习的理由。 开发技术越是上层,高级,那么对底层封装的就越深。我学习汇编语言的目的,不是用它来开发应用软件,因为那是高...

FORM开发笔记

1, 界面对行循环后在回到循环前的行 v_current_record number:=Get_Block_Property('block名称', Current_Record); --返回当前行号 go_record(v_current_record); --回到以前的当前行 2,Form中的系统变量,它存在于一个Form的整个运行时期的会话之中,变量包...

oracle pl/sql 变量

一、变量介绍在编写pl/sql程序时,可以定义变量和常量;在pl/sql程序中包括有:1)、标量类型(scalar)2)、复合类型(composite) --用于操作单条记录3)、参照类型(reference) --用于操作多条记录4)、lob(large object)    二、标量(scalar)——常用类型1)、在编写pl/sql块时,如果要使用...

deppin Linux下安装docker

首先楼主用的是deppin15.11   docker 简介:Docker作为一个软件集装箱化平台,可以让开发者构建应用程序时,将它与其依赖环境一起打包到一个容器中,然后很容易地发布和应用到任意平台中。         思想:              1.集装箱             2.标准化             3.隔离           核...