深入理解JVM虚拟机第二十二篇:详解JVM当中与操作数栈相关的字节码指令

news2024/10/7 20:34:57

大神链接:作者有幸结识技术大神孙哥为好友,获益匪浅。现在把孙哥视频分享给大家。

孙哥链接:孙哥个人主页
作者简介:一个颜值99分,只比孙哥差一点的程序员
本专栏简介:话不多说,让我们一起干翻JVM

本文章简介:话不多说,让我们讲清楚JVM当中与操作数栈相关的字节码指令

文章目录

一: 操作数栈字节码指令

1:编写源码

2:javap解释整理字节码

3:通过jclasslib查看字节码指令

二:字节码分析

1:最全字节码指令分析

2:面试题


一: 操作数栈字节码指令

1:编写源码

public class OperandStackTest {
    public void testAndOperation(){
        byte i = 15;
        int j = 8;
        int k = i+j;
    }
}

2:javap解释整理字节码

        想要查看字节码文件呢,我们有两种方式,第一种就是直接进行javap,第二种就是使用jclasslib进行查看,我们先使用第一种。

PS D:\code\study\hadoop\shit\target\classes> javap -verbose .\OperandStackTest.class
Classfile /D:/code/study/hadoop/shit/target/classes/OperandStackTest.class
  Last modified 2023年11月9日; size 421 bytes
  SHA-256 checksum 487149a1edc4d19af0b1fe2369086c27c8765ff5e011491d1028d4f6cf1d9746
  Compiled from "OperandStackTest.java"
public class OperandStackTest
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #2                          // OperandStackTest
  super_class: #3                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #3.#19         // java/lang/Object."<init>":()V
   #2 = Class              #20            // OperandStackTest
   #3 = Class              #21            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               LOperandStackTest;
  #11 = Utf8               testAndOperation
  #12 = Utf8               i
  #13 = Utf8               B
  #14 = Utf8               j
  #15 = Utf8               I
  #16 = Utf8               k
  #17 = Utf8               SourceFile
  #18 = Utf8               OperandStackTest.java
  #19 = NameAndType        #4:#5          // "<init>":()V
  #20 = Utf8               OperandStackTest
  #21 = Utf8               java/lang/Object
{
  public OperandStackTest();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LOperandStackTest;

  public void testAndOperation();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        15
         2: istore_1
         3: bipush        8
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: return
      LineNumberTable:
        line 3: 0
        line 4: 3
        line 5: 6
        line 6: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   LOperandStackTest;
            3       8     1     i   B
            6       5     2     j   I
           10       1     3     k   I
}
SourceFile: "OperandStackTest.java"

3:通过jclasslib查看字节码指令

        首先进行recompile Java文件为字节码文件,然后我们在idea的view下找到这个:

        show ByteCode with JclassLib:

        最终显示结果如下:

二:字节码分析

1:最全字节码指令分析

public class OperandStackTest {
    public void testAndOperation(){
        byte i = 15;
        int j = 8;
        int k = i+j;
    }
}
 0 bipush 15
 2 istore_1
 3 bipush 8
 5 istore_2
 6 iload_1
 7 iload_2
 8 iadd
 9 istore_3
10 return

         bipush将15这个值push到了操作数栈中,此时我们的操作数栈就有了第一个值。我们需要回顾一下:byte、short、char、boolean、int类型在声明之后往数组中进行存放的时候都会保存为int类型。也就是说虽然定义的是byte类型,但是存放到数组中就是int类型

        栈帧在调用之初,栈帧被创建完成,其中的操作数栈和局部变量表是空的。PC寄存器中存放着第一条要执行的指令的地址。

        istore_1将这个值从操作数栈放到了局部变量表中索引为1的位置,为什么不是0呢?因为这不是一个静态方法,索引为零的位置存放的是this。

        此时的操作数栈就成了空,这是一个出栈的操作。过程中会修改PC寄存器中的索引值为下一条命令的索引值。

       过程中会修改PC寄存器中的索引值为下一条命令的索引值。

       同样的道理,8也会经过bipush和istore_2,然后最终的结果如下:

        iload_1和iload_2命令会将变量中索引为1,2的数据取出来分别放到局部变量表中

        最终的运行结果如下:

        紧接着会进行一个iadd命令,这个命令呢会使数据进行出栈,然后相加。值得注意的是,字节码指令需要被翻译为机器指令,机器指令操作CPU进行相加。然后将结果23放到操作数栈当中。

        运行结果如下:

        

        最终,istore_3将这个值从操作数栈放到了局部变量表中索引为3的位置, 此时的操作数栈就成了空,这是一个出栈的操作。过程中会修改PC寄存器中的索引值为下一条命令的索引值。

        最终的运行结果如下:

        我们也注意到,局部变量表长度为4,操作数栈深度为2(看javap的结果),这也是与图中可以对应上的,唯一区别的是局部变量表中的因为篇幅原因,this的位置也就是索引为0的变量槽没有展示出来。 

        补充说明:

        我们注意到bipush是将一个byte类型的数据push到操作数栈中基于int类型进行存储,还有sipush,这个字节码指令的含义是将short类型的数据push到操作数栈中基于int类型进行存储。

        如果方法有返回值,那么最终的字节码指令将由return会变成ireturn。也就是将值做了一个返回,这个栈帧就结束了,另外一个调用此方法的栈帧会立即调用一个aload_x这样的一个操作,将上一个方法的返回值加载到此栈帧的操作数栈中。

    public int getSum(){
        int m = 10;
        int n = 20;
        int k = m+n;
        return k;
    }

    public void testGetSum(){
        //aload_0获取上一个栈帧返回的结果,并保存在操作数栈中。
        int i = getSum();
        int j = 10;
    }

2:面试题

        i++ 和 ++j的区别是什么?

       此问题,后续我们在字节码文章中会跟大家进行探讨

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VUE页面导出PDF方案

1&#xff0c;技术方案为&#xff1a;html2canvas把页面生成canvas图片&#xff0c;再通过jspdf生成PDF文件&#xff1b; 2&#xff0c;安装依赖&#xff1a; npm i html2canvas -S npm i jspdf -S 3&#xff0c;封装导出pdf方法exportPdf.js: // 页面导出为pdf格式 //titl…

简单选择排序(c语言代码实现)

选择排序&#xff1a;简单选择排序&#xff08;不稳定的排序&#xff09; 简单选择排序是一种基础的排序算法&#xff0c;它的基本思路是在未排序的序列中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;将其与序列的第一个元素进行交换&#xff0c;然后在剩余的未…

MySQL-基础篇

文章目录 第一章 MYSQL 概述数据库相关概念MySQL 数据库下载安装启动和停止 MySQL客户端连接解决&#xff1a;mysql 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。配置 Path 环境变量解决&#xff1a;net start mysql80 发生系统错误 5。 拒绝访问。MYSQL 的…

IntelliJ IDEA - Git Commit 后 Commit 窗口不消失解决方案

这个现象是在 2023 年版本后开始的&#xff0c;一开始以为是 Mac 系统的原因&#xff0c;后来发现原来 Windows 也这样&#xff0c;所以应该只跟 IDEA 版本有关 可以看到左侧 commit 后&#xff0c;这个侧边栏还在&#xff0c;按理讲在以前的版本是之前消失&#xff0c;这样使…

layui table合并相同的列

table.render({elem: #samples,url: /index/Develorderss/samplelists?od_idod_id //数据接口,page: { //支持传入 laypage 组件的所有参数&#xff08;某些参数除外&#xff0c;如&#xff1a;jump/elem&#xff09; - 详见文档layout: [prev, page, next, count,skip,limit]…

TCP发送窗口、接收窗口以及其工作原理

1*KvfIrP_Iwq40uVdRZYGnQg.png 上面的图表是从发送方的角度拍摄的快照。我们可以将数据分为4组&#xff1a; 1.已发送并已确认的字节&#xff08;蓝色&#xff09;2.已发送但尚未确认的字节&#xff08;黄色&#xff09;3.未发送但接收方准备好接收的字节&#xff08;绿色&…

【C++】C++静态成员函数,类名直接调用

静态成员函数可以通过类名直接调用&#xff0c;不用创建对象。例如&#xff1a;ClassName::Func();通过类名直接调用因为不用创建对象所以不会运行类的构造方法。适合用于初始化。 参考&#xff1a; C【6】对静态成员函数的用法说明C调用成员函数的几种方法总结C static静态…

大数据毕业设计选题推荐-农作物观测站综合监控平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Linux 多线程编程详解

目录 为什么要使用多线程 线程概念 线程的标识 pthread_t 线程的创建 向线程传入参数 线程的退出与回收 线程主动退出 线程被动退出 线程资源回收(阻塞方式) 线程资源回收(非阻塞方式) 为什么要使用多线程 在编写代码时&#xff0c;是否会遇到以下的场景会感觉到难以…

LINUX入门篇【4】开发篇--开发工具vim的使用

前言&#xff1a; 从这一篇开始&#xff0c;我们将正式进入使用LINUX进行写程序和开发的阶段&#xff0c;可以说&#xff0c;由此开始&#xff0c;我们才开始真正去使用LINUX。 介绍工具&#xff1a; 1.LINUX软件包管理器yum&#xff1a; 1.yum的介绍&#xff1a; 在LINUX…

Swift--量值与基本数据类型

系列文章目录 第一章: Swift–量值与基本数据类型 文章目录 系列文章目录前言对学习过程做一个记录 变量和常量命名规范注释 元祖类型可选类型拆包 typealias 前言 对学习过程做一个记录 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 变量和常量 …

十分钟理解回归测试(Regression Testing)

回归测试是一个系统的质量控制过程&#xff0c;用于验证最近对软件的更改或更新是否无意中引入了新错误或对以前的功能方面产生了负面影响&#xff08;比如你在家中安装了新的空调系统&#xff0c;发现虽然新的空调系统可以按预期工作&#xff0c;但是本来亮的等却不亮了&#…

Leetcode刷题【hot100】盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例…

单例模式 rust和java的实现

文章目录 单例模式介绍应用实例&#xff1a;优点使用场景 架构图JAVA 实现单例模式的几种实现方式 rust实现 rust代码仓库 单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是最简单的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建…

uboot 和 内存地址

前言 在使用 uboot 升级的时候&#xff0c;有个疑问&#xff1a; 通过 tftp 下载的 bin 文件&#xff0c;我该暂存在哪段内存空间&#xff1f;换句话说&#xff0c;哪段内存空间可供我存放临时数据&#xff1f; 带着这个疑问&#xff0c;开启今天的 uboot 和 内存地址 研究之旅…

CSS特效004:hover图片,显示文字或附加层

css实战中&#xff0c;时常会碰见鼠标放在某个区块上&#xff0c;显示出一段文字或者其他附加信息。思路是利用position的层叠关系&#xff0c;将文字层放在图片的上面&#xff0c;display:none; hover的时候层 display&#xff1a;block。 效果图 源代码 /* * Author: 大剑师…

NR UE capability FeatureSetCombination的查看方法

下面是UEcapability中根据协议中的描述总结的NR CA和EN-DC组合的查看方法&#xff0c;主要内容在38.331/36.331中。比较关键的IE就是FeatureSetCombination。 FeatureSetCombination对应的是FeatureSet entries的二维矩阵。 每个FeatureSetsPerBand 包含适用于相关band combin…

伦敦金股票代码是什么?

伦敦金是跟踪实时的现货黄金价格走势的差价合约交易&#xff0c;它的代码一般是LLG、GOLD&#xff0c;但也有一些货币交易平台会显示为XAU。伦敦金不是股票交易&#xff0c;因此没有四位数或六位数的股票代码&#xff0c;但伦敦金交易品种单一&#xff0c;投资者不用在数千支股…

亚马逊云科技海外服务器初体验

目录 前言亚马逊云科技海外服务器概述注册使用流程实例创建性能表现用户体验服务支持初体验总结 前言 随着云原生技术的飞速发展&#xff0c;越来越多的企业和开发者选择云服务器来作为自己的使用工具&#xff0c;云原生技术的发展也促进了云服务厂商的产品发展&#xff0c;所…

CSS3 2D、3D转换

一、CSS3 2D转换&#xff1a; CSS3转换可以对元素进行移动、缩放、转动、拉长或拉伸。 2D变换的方法&#xff1a;translate()、rolate()、scale()、skew()、matrix()。 <style> div { width:200px; height:100px; background-color:red; /* Rotate div */ tran…