栈帧内的数据结构

  • 局部变量表(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. 【进阶之路】Java的类型擦除式泛型

    Java选择的泛型类型叫做类型擦除式泛型.什么是类型擦除式泛型呢?就是Java语言中的泛型只存在于程序源码之中,在编译后的字节码文件里,则全部泛型都会被替换为原来的原始类型(Raw Type),并且会 ...

  2. javascript 特殊字符 注意转义

  3. 【原创】在macOS Big Sur (Silicon M1, ARM)中配置ASP运行环境

    亲测有效,转载请附原文地址. 一,安装Parallels Desktop,注意选择支持ARM的版本. 二,注册 Windows Insider Preview Downloads 账号,通过以下链接下 ...

  4. Ivy入门笔记

    安装过程 命令行安装 下载和安装JDK5.Eclipse3.5.Ant 1.8.Ivy 2.2: 安装JDK:成功标志:在命令行下运行java命令,得到java命令行帮助: 安装Ant:解压Ant,在 ...

  5. 【翻译稿】Behavior Driven Development (BDD)行为驱动开发

    这是一篇翻译稿,方便给不知道BDD的同学扫盲.原文链接:What is BDD (Behavior Driven Development)? | Agile Alliance Definition定义 ...

  6. 题解 Lost My Music

    传送门 多明显的斜率式然而我没有看出来 然而不管是我乱搞的思路还是正解的凸包思路都需要一个可持久化栈 考场上想到可持久化单调栈,但不会实现-- 其实单调栈不管是否可持久化都能倍增弹栈 但普通单调栈本来 ...

  7. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...

  8. zoolkeeper 的Curator的分布式锁

    RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3) CuratorFramework client = CuratorFram ...

  9. servlet防止表单重复提交

    日常开发中,防表单重复提交是一项必须的工作 我们可以利用javascript防止表单重复提交,但是利用javascript防止表单重复提交会出现一个新的问题 因为某些用户可能会绕过script代码直接 ...

  10. 【mysql】截取查询分析

    1. 慢查询日志 1.1 是什么 (1)MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL ...