栈帧内的数据结构

  • 局部变量表(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学习笔记:栈帧的更多相关文章

  1. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  2. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  3. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

  4. JVM学习笔记-JVM模型

    JVM学习笔记 == 标签(空格分隔): jvm 学习笔记全部来自于<深入理解java虚拟机>总结 jvm内存示意图 虚拟机栈(Java Virtual Machine Stacks): ...

  5. JVM学习笔记——字节码指令

    JVM学习笔记——字节码指令 字节码 0与 1是计算机仅能识别的信号,经过0和1的不同组合产生了数字之上的操作.另外,通过不同的组合亦产生了各种字符.同样,可以通过不同的组合产生不同的机器指令.在不同 ...

  6. JVM学习笔记-第六章-类文件结构

    JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...

  7. JVM学习笔记——内存结构篇

    JVM学习笔记--内存结构篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存结构部分 我们会分为以下几部分进行介绍: JVM整体介绍 程序计数器 虚拟机栈 本地方法栈 堆 方法 ...

  8. JVM学习笔记——类加载和字节码技术篇

    JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...

  9. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  10. 【Java虚拟机】JVM学习笔记之GC

    JVM学习笔记二之GC GC即垃圾回收,在C++中垃圾回收由程序员自己来做,例如可以用free和delete来回收对象.而在Java中,JVM替程序员来执行垃圾回收的工作,下面看看GC的详细原理和执行 ...

随机推荐

  1. Qt-可编辑的ListView

    新建一个QML项目, main.cpp不动如下: #include <QGuiApplication> #include <QQmlApplicationEngine> int ...

  2. HttpRunner3源码阅读:7.响应后处理 response.py

    response 上一篇说的client.py来发送请求,这里就来看另一个response.py,该文件主要是完成测试断言方法 可用资料 jmespath[json数据取值处理]: https://g ...

  3. CVE-2018-12613总结

    1.漏洞基础介绍 1.1漏洞背景 phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库.借由此We ...

  4. C++ 继承方式 与 普通方式 对比

    1 //C++ 继承 2 //继承是面向对象三大特性之一 3 4 #include <iostream> 5 #include <string> 6 using namespa ...

  5. 干了5年Android开发,突然感觉自己啥也不会,啥也不想干,还要继续吗?

    这是在某论坛看到的一名同行的吐槽: 我干了差不多5年,不过给人感觉跟只有两三年的人一样. 我觉得我不适合干程序员,主要是新东西的接受能力比其他人慢,Android技术又更新得很快,感觉总是跟不上.年纪 ...

  6. Devcpp(Dev-C++)代码编辑的快捷键

    转自:https://blog.csdn.net/u010940020/article/details/43735549 这里记录一些个人使用Devcpp时,摸索出来的代码编辑快捷键,感觉非常有用.如 ...

  7. 慕慕生鲜上线&&腾讯云服务器配置准备

    1.购买服务器并配置环境 1.1 购买 618购买了腾讯云服务器三年最低配置(1核2G 1Mbps 50G云盘),一时激动忘记了购买前领优惠券,痛失25元. 1.2 环境配置 系统是 CentOS L ...

  8. Go连接到Linux服务器进行操作-执行shell命令&&上传文件

    Go连接到Linux服务器进行操作 使用密码连接Linux服务器 package main import ( "fmt" "golang.org/x/crypto/ssh ...

  9. HTTP协议特性、HTML标签

    HTTP协议 超文本传输协议,规定浏览器和服务端数据交互格式 四大特性 基于请求响应. 在TCP/IP协议之上的应用层协议. 无状态(不能保存用户信息,后来为了保存用户信息,诞生了cookie,ses ...

  10. noip12

    T1 类似于昨天的t3,先用单调栈求出管控区间,然后暴力求解30pts 我没取模还没开longlong,然后就爆0了 正解: 仍然是用单调栈求一下区间,用线段树维护一下余数,对于i所对应的区间\([l ...