IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java随笔-方法执行与栈帧 -> 正文阅读

[Java知识库]Java随笔-方法执行与栈帧

编译与汇编

若是想了解方法执行流程就需要知道字节码汇编后内容。

  1. java文件编译后会生成class文件。
    请添加图片描述
    对于图中的代码编译后与编译前差别不大,区别在于:
  • 源代码中若是没有构造方法,编译后会自动添加构造方法。
  • 源代码中的注释编译后都没有了,注释原本就如此。
  1. 使用javap对class文件进行反汇编。

输入javap
输入javap汇编后得到如下内容。

  • 常量池。
    请添加图片描述
    此时的运行时常量池里面存储着Student类涉及到的方法,常量等等信息。
  • 构造方法(构造函数)
    javap汇编前:
    public Student() {
    }

javap汇编后:
请添加图片描述

  • main方法
    javap汇编前:
    public static void main(String[] args) {
        Student student = new Student();
        student.study();
        student.hashCode();
    }

javap汇编后:
请添加图片描述

  • study方法
    javap汇编前:
    public void study() {
        int i = 9;
        int j = 10;
        int k = (i + j) * 11;
        System.out.println(k);
    }

javap汇编后:
请添加图片描述

方法执行与栈帧

以执行study()为例进行讲解。
代码如下:

public class Student {

    public static void main(String[] args) {
        Student student = new Student();
        student.study();
        student.hashCode();
    }
    /**
     *  测试方法
     */
    public void study(){
        int i = 9;
        int j = 10;
        int k = (i + j)  * 11;
        System.out.println(k);
    }
}

首先需要了解study方法汇编后的的代码和涉及JVM的运行时数据区。
请添加图片描述

  • 实例方法中,索引为0的位置默认为this,表示对该实例对象的持有。
  • 由于先调用的main方法,所以栈帧-main位于栈底。

执行流程:

  1. study()方法在main中进行调用,调用study时main的代码偏移量为9。
    请添加图片描述
    汇编中:9: invokevirtual #10 对于的代码是 student.study(),所以此时的方法返回地址应该是9,程序计数器为9。程序计数器记录当前正在执行的方法代码偏移量,方法出栈后,下一个执行的方法执行的偏移量可能会和上一个方法最后的偏移量相同,所以出现重复计数属于正常情况。有些字符串看不懂可以参考java字节码指令。
  2. 执行study的 0: bipush 9,这其实是两行指令,所以下一行指令直接从2开始。0:bipush,1:9,意思是将9(i = 9)压入操作数栈中,此时程序执行到0位置,所以程序计数器为0。
    请添加图片描述
  3. 执行 2: istore_1。此时将9从操作数栈中出栈,存储在局部变量表为1的位置,同时程序计数器为2。
    请添加图片描述
  4. 执行3: bipush 10(j = 10),将10压入操作数栈,程序计数器为3.
    请添加图片描述
  5. 执行5: istore_2。10出栈,进入局部变量表索引为2的位置,程序计数器为5.
    请添加图片描述
  6. 执行6: iload_1。iload_1和前面的istore_1指的都是9,将9加载进操作数栈中,程序计数器为6.

请添加图片描述
6. 执行7: iload_2。iload_2和前面的istore_2指的都是10,只是操作不同。将10加载进操作数栈中,程序计数器为7.

请添加图片描述
操作数栈也是栈需要遵循栈的规则,后入栈的放在先入栈的上面。

  1. 执行iadd,也就是相加操作。将9和10依次出栈,可能在cpu中进行相加操作,操作数栈没有处理数据的功能,将9+10=19的结果再次压入操作数栈中,此时程序计数器为8。
    请添加图片描述

  2. 执行9: bipush 11。将将要乘的11压入操作数栈中,程序计数器为9.
    请添加图片描述

  3. 执行imul,就是相乘操作。将11和19出栈,计算后将11*19=209压入操作数栈,程序计算器为11.
    请添加图片描述

  4. 执行12: istore_3。将操作数栈中的209出栈,存储在局部变量表索引为3的位置。
    请添加图片描述

  5. 执行13: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream,就是调用 System.out.println()方法,此时程序计数器为13。

  6. 执行12: istore_3。将局部变量表中索引为3的209压入操作数栈,此时程序计数器为16.
    请添加图片描述

  7. 执行17: invokevirtual #23。将209出栈,然后执行System.out.println(209)打印输出,此时程序计数器为17.

  8. 执行20:return。此时要返回方法返回地址9,该方法到此执行完毕,执行出栈操作,然后main从方法返回地址9的位置往下执行。

本地方法栈

调用getClass()或hashCode()都属于本地方法,使用native修饰的都属于本地方法。

    @IntrinsicCandidate
    public final native Class<?> getClass();
    ...
    @IntrinsicCandidate
    public native int hashCode();

本地方法栈和虚拟机栈结构相同,物理上共用同一块内存,但是本地方法汇编后和java汇编后不一样,所以程序计数器不能用来记录本地方法。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:48:23  更:2022-03-06 12:53:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:43:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码