• jvm 二之 栈帧内部结构


    栈帧内部结构

    1、内存结构

    在每一个方法 栈帧中都会有自己独立的,其中包括

    • 1、局部变量表 (存放当前方法对应的局部变量);
    • 2、操作数栈 (或表达式栈);
    • 3、动态连接 (或指向运行时常量池的方法引用)
    • 4、方法出口 (或方法正常退出或者异常退出的定义)

    栈帧包含方法的所有信息
    使用 javap -v Demo03.class 查看转成汇编后的源码

    在这里插入图片描述

    2、idea 分析插件

    打开idea 中的settings > plugins 搜索 jclasslib 插件
    重启后点击 view > 选择 show bytecode with jclasslib

    在这里插入图片描述
    查看分析
    在这里插入图片描述

    一、局部变量表

    局部变量表中的变量只在 当前方法 调用中有效。
    在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。
    当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。

    每一个方法都有一个局部变量表

    1.1、Slot(变量槽–index)

    public static void main(String[] args) {
        String str = "mayikt";
        int j = 20;
        double d = 66.66;
        boolean b = true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如下: JVM会为局部变量表中每一个变量分配变量槽

    • args 参数: 在 局部变量表中 slot 索引 0 的位置
    • str 参数: 在 局部变量表中 slot 索引 1 的位置
    • j 参数: 在 局部变量表中 slot 索引 2 的位置
    • d 参数: 在 局部变量表中 slot 索引 3 的位置 (double 会占用两个槽位)
    • b 参数: 在 局部变量表中 slot 索引 5 的位置

    在这里插入图片描述

    局部变量表最基本的存储单元就是变量槽。

    • 32位以内的类型只占用一个slot (包括returnAddress类型),
    • 64位的类型(long和double)占用两个slot。
    • short,byte,boolean 等数据也占用一个变量槽,因为jvm会在存储时将上述变量转为int类型(变量槽是最基本存储单元,无法分割,只能整个使用)。

    1.2、变量槽的复用

    public static void mayikt002() {
        int a = 0;
        {
            int b=30;
            System.out.println("mayikt");
        }
        int c = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此处原因就是JVM对变量槽有一个复用性为

    • 变量b 使用了变量槽 1, 超出其作用域后不再生效,
    • 变量c 发现变量槽 1 其作用域后超出, 直接占据了 b 的位置

    在这里插入图片描述

    1.3、变量槽中的 this

    如果当前的方法是实例方法或者是构造方法 则jvm默认会在局部变量表中创建 一个
    当前对象 this , 存入在我们当前方法对应的局部表第0个位置 这样我们就可以在实例方法中 使用 this,静态方法不会。

    public void mayikt() {
        int j = 20;
    }
    
    • 1
    • 2
    • 3

    变量槽中默认存在 this 变量

    在这里插入图片描述

    二、操作数栈

    mian 调用 a, a 调用 b ,b 调用c , c调用 d, 方法会压入到栈空间中
    而操作数栈是值变量的操作进行的压栈操作,从而可以执行相关 加减乘除 操作

    2.1、基础操作 指令解析

    当前代码

    public int compute() {
        int a = 10;
        int b = 20;
        int c = (a + b) * 10;
        return c;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    转汇编后的代码 , javap -v xxxx.class

    在这里插入图片描述

             0: bipush        10              //  将一个8位带符号整数压入栈
             2: istore_1                      //  变量槽 1   a 存入 10      
             3: bipush        20              //  将一个8位带符号整数压入栈        
             5: istore_2                      //  变量槽 2   b 存入 20  
             6: iload_1                       //  获取槽1  变量a=10;
             7: iload_2                       //  获取槽2  变量a=20;
             8: iadd                          //  i执行int类型的加法 10+20=30
             9: bipush        10              //  将一个8位带符号整数压入栈 10
            11: imul                          //  imul 执行int类型的乘法 30*10=300
            12: istore_3                      //  变量槽3  c存入计算结果 300 
            13: iload_3                       //  获取槽3  变量c=300;
            14: ireturn                       //  方法返回最后读取的变量槽数据
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2、i++ 和 ++i 解析

    i++

    执行+1 前压入的栈数据, 栈顶数据是 0
    在这里插入图片描述
    ++i

    执行+1 后压入的栈数据, 栈顶数据是 1
    在这里插入图片描述

    2.3、栈溢出

    StackOverflowError(栈溢出)
    StackOverflowError代表的是,当栈深度超过虚拟机分配给线程的栈大小时就会出现此error

    默认是有最大深度的, 常出现在递归调用中

    2.4、方法出口

    方法返回地址

    2.5、动态链接

    在操作数栈中找到被调用的子方法就是动态链接

    动态链接: 每个栈帧都保存了 一个可以指向当前方法所在类的 运行时常量池,
    目的是: 当前方法中如果需要调用其他方法的时候, 能够从运行时常量池中找到对应的符号引用, 然后将符号引用转换为直接引用,然后就能直接调用对应方法, 这就是动态链接

    三、常量池

    什么是常量池(Constant Pool)
    java经过编译后生成的.class文件,是Class文件的资源仓库。

    常量池分类:

      1. 运行时常量池 ,jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在元空间中,我们常说的常量池,就是指方法区中的运行时常量池
      1. 静态常量池 class文件的关键信息,类和接口的全限定名字段的名称和描述符方法的名称和描述符,以及被 final 修饰的常量值等,如 数量值 字符串值 以及字面量(Literal)和符号引用(Symbolic References) ,如: 类引用 字段引用 方法引用
      1. 字符串常量池 顾名思义,存放字符串, 如: Strng, StringBufferStringBuffer 等, jdk7 之前 方法区JDK7 存放在堆中JDK 8方法区改 元空间 字符串常量池还是存放在我们堆中

    在这里插入图片描述

    元空间就是之前的方法区
    在这里插入图片描述

  • 相关阅读:
    笔试题-构建非二叉树,且非递归遍历-利用栈
    秒杀项目的总结及面试常见问题
    修谱是一件好事:薪火相传,让老一辈庇护和提携后辈,造福乡里宗亲
    Redis分布式锁
    Power BI前端设计:深度探索与实战技巧
    PY32F003F18串口printf功能
    C++~auto关键字
    Hive面试题系列第七题-同时在线问题
    切换至root用户时,命令提示符颜色为白色,如何修改?
    Linux Command htpasswd 创建密码文件
  • 原文地址:https://blog.csdn.net/qq_41463655/article/details/126081614