jvm学习笔记:栈帧
栈帧内的数据结构
局部变量表(Local Variables):记录非静态方法的this指针、方法参数、局部变量
操作数栈(Operand Stack):用于计算的栈结构
动态链接(Dynamic Link):指向运行时常量池的方法引用
方法返回地址(Return Address):方法正常退出或异常退出的定义,以及方法间返回值传递(注意: java中的方法除了正常返回还可能因为异常退出,所以方法返回地址不一定就是方法退出的地址)
附加信息
局部变量表
Each frame contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile-time and supplied in the binary representation of a class or interface along with the code for the method associated with the frame
主要存储方法的参数、方法内的局部变量,数据类型包括基本数据类型、对象引用(数值地址)、返回地址。局部变量表具有以下特点:
- 局部变量表数组的容量大小在编译时期确定,后面不会变化
- 局部变量表是每个线程私有的,不存在线程安全问题
非静态方法的局部变量表
- 构造方法、实例方法会自带一个this引用变量
- static方法不能使用this的原因:静态方法的局部变量表中不带有this的引用
变量槽(Slot)
局部变量表中最基本的存储单元,每个槽大小32位
- 局部变量表是index0开始的数组,数组的每个元素我们称为变量槽
- 局部变量表中,32位以内类型占一个槽(int),64位占两个槽(long、double),引用类型占用一个槽
- 调用占有两个槽的变量使用起始索引
slot重复利用
栈帧中局部变量表的槽位是可以复用的,如果某个局部变量的作用域已经结束了,那么在它后面声明的局部变量可以使用它的槽位
这样的设计使局部变量表的空间利用率更高,不会造成空位的情况。
重复利用的例子:
public void test1(){
int a = 0;
{
int b = 0;
b = a + 1;
}
int c = 1;
}
上面代码的局部变量表如图,可见b和c的槽位都是index=2,也就是说b的作用域结束后,c会重复使用b的槽位。
局部变量表与垃圾回收
- 局部变量表中的变量是重要的垃圾回收节点,只有被局部变量表中直接或者间接引用的对象才不会被回收
操作数栈(Operand Stack)
Each frame contains a last-in-first-out (LIFO) stack known as its operand stack. The maximum depth of the operand stack of a frame is determined at compile-time and is supplied along with the code for the method associated with the frame
操作数栈,在方法执行的过程中根据字节码指令,往栈中写入或提取数据
- 某些字节码指令将值压入操作数栈,其他指令又可以取出数值,使用后又可以再压入栈
- 比如:复制操作、交换、求和
- 字节码指令由执行引擎翻译成机器指令
- 操作数栈是一个栈帧中的结构,它随着一个方法的开始执行而被创建
- 每一个操作数栈都在编译时确定了固定的深度,这个深度保存在code属性的max_stack值
- 32位占一个栈深度、64位占两个栈深度
i++和++i区别
情景1
public void test(){
int i1 = 10;
i1++;
int i2 = 20;
++i2;
}
上面代码编译的字节码如上图,可见i++和++i编译出来的字节码其实是一样的,首先都是bipush指令将i的初值压入操作数栈,然后 用istore指令出栈并存入局部变量表。然后用iinc指令将局部变量表中的数据取出并+1
情景2
public void test(){
int i1 = 10;
int d1 = i1++;
int i2 = 20;
int d2 = ++i2;
}
上面代码编译后字节码如图,可以发现用i++赋值和++i赋值的字节码是有差异的。
int d = i++的情况:首先还是用 bipush指令把初始值放入操作数栈,然后用istore取出并存入局部变量表。在给d赋值时,会先用 iload指令读取局部变量表的 i 到操作数栈(暂时存在栈中,不出栈),然后用 iinc指令为局部变量表的 i 加1,完成后再用istore指令将操作数栈中没有加一的 i 出栈,存到新的局部变量表槽中。
int d = ++i的情况:与上述情况唯一的不同是,这种情况会先调用 iinc 指令将局部变量表的 i 加一,然后再用 iload指令将加一后的 i存入操作数栈,最后用 istore赋值给局部变量
情景3(丧心病狂)
public void test(){
int i1 = 10;
i1 = i1++;
int i2 = 10;
i2 = ++i2;
}
上述代码的字节码如上图
i = i ++情况:首先使用了 bipush 将10 压入了操作数栈,然后使用了 istore将初值10出栈并存入局部变量表,然后用 iload指令将局部变量 10 入栈到了操作数栈(接下来的操作该数值没改变)。接着使用了 iinc 指令将局部变量 i 取出、入栈、加一、出栈、存入局部变量表。这一过程没有改变最初入栈的初值10。最后,使用了 istore 指令将这个 10 覆盖了之前加一的局部变量。所以这种情况其实 i 的值没变。
i = ++i情况:同样,还是先用bipush、istore将初值10存入了局部变量表。因为++再i之前,所以先使用了 iinc 指令将局部变量表中的 10+1 改成了 11,然后再用 iload、istore指令来给 i 赋值,最终i会变成 11
其实通过上面两种情况的分析,我们可以发现,第二种情况下最后的iload、istore指令其实是没有实际意义的,它们只是将 i 入栈操作数栈又出栈存入原来的局部变量表位置。
动态链接(Dynamic Linking)
Each frame contains a reference to the run-time constant pool for the type of the current method to support dynamic linking of the method code
每个栈帧中包含的指向运行时常量池中该栈帧所属方法的引用
- 指向运行时常量池的方法引用
- 动态链接的作用就是将符号引用转换为直接引用
jvm学习笔记:栈帧的更多相关文章
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- java之jvm学习笔记十三(jvm基本结构)
java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...
- JVM学习笔记-JVM模型
JVM学习笔记 == 标签(空格分隔): jvm 学习笔记全部来自于<深入理解java虚拟机>总结 jvm内存示意图 虚拟机栈(Java Virtual Machine Stacks): ...
- JVM学习笔记——字节码指令
JVM学习笔记——字节码指令 字节码 0与 1是计算机仅能识别的信号,经过0和1的不同组合产生了数字之上的操作.另外,通过不同的组合亦产生了各种字符.同样,可以通过不同的组合产生不同的机器指令.在不同 ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- JVM学习笔记——内存结构篇
JVM学习笔记--内存结构篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存结构部分 我们会分为以下几部分进行介绍: JVM整体介绍 程序计数器 虚拟机栈 本地方法栈 堆 方法 ...
- JVM学习笔记——类加载和字节码技术篇
JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- 【Java虚拟机】JVM学习笔记之GC
JVM学习笔记二之GC GC即垃圾回收,在C++中垃圾回收由程序员自己来做,例如可以用free和delete来回收对象.而在Java中,JVM替程序员来执行垃圾回收的工作,下面看看GC的详细原理和执行 ...
随机推荐
- Matlab的datenum()函数用法
Matlab的datenum()函数用法 将日期和时间转换为日期序列值 datenum 函数创建一个数值数组,将每个时间点表示为从 0000 年 1 月 0 日起的天数.数值还能表示以天为单位的过去时 ...
- Python: 解析crontab正则,增加+操作
以下是使用Python解析crontab时间格式的一个类, 同时minute和hour支持了 + 的操作. 记录一下备忘. 其中的line参数是字符串分拆后的格式, 包含了 "week&qu ...
- .Net Core微服务——Consul(4):主从、集群
延续上一篇的话题继续,顺便放上一篇的传送门:点这里. 集群的必要性 consul本身就是管理集群的,现在还需要给consul搞个集群,这是为啥?因为consul单点也容易挂啊!万一管理集群的consu ...
- Python中input()函数用法
input()函数获取用户输入数据,实现用户交互 语法格式: 变量 = input("提示信息") input()返回的是字符串,无论输入的是数字还是字符串,默认的输入结束键是回车 ...
- KMP算法的详细解释
什么是kmp算法呢?这是一个处理字符串的算法,用来判断给出的模式串p是否存在于文本串t中(p的长度小于t). 在本文中,字符串储存在字符数组中,并且第一个字符放在下标为1的元素中. 那么如何理解kmp ...
- Notepad++的NppFTP插件连接linux操作系统
Notepad++的NppFTP插件连接linux操作系统 下载地址:https://notepad-plus-plus.org/downloads/v8.1.2/ 1.安装Npp_FTP插件 两种方 ...
- 实战爬取拷背漫画-Python
一.抓包获取链接 以爬取<前科者>为例 获取搜索链接 https://api.copymanga.com/api/v3/search/comic?limit=5&q=前科者 ...
- JavaWeb项目实战-油画商城
整个项目都已经上传到github-mmgallery上,供有需要的读者使用,主要文件来自于csdn,区别是csdn中的项目数据存储在MySQL中,本项目数据存储在Xml文件中.课件和学习视频课程来自M ...
- 漏洞复现|Dubbo反序列化漏洞CVE-2019-17564
01漏洞描述 - Apache Dubbo支持多种协议,官方推荐使用Dubbo协议.Apache Dubbo HTTP协议中的一个反序列化漏洞(CVE-2019-17564),该漏洞的主要原因在于当A ...
- noip36
开场先看一遍题面,凭着错误的感觉t3叫naive是一个原因,312开局.然后就死的很惨. T1 朴素暴力40pts,细想就有80pts,然而我只写了十分钟左右就爬回T3了,所以... 其实都是借口 正 ...