《深入理解Java虚拟机》 JAVA 字节码指令 基础

这篇具有很好参考价值的文章主要介绍了《深入理解Java虚拟机》 JAVA 字节码指令 基础。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.操作数栈

解释时,JVM会为方法分配一个栈帧,而栈帧又由 局部变量表,操作数帧,方法引用,动态链接 组成

方法中的每条指令执行时,要求该指令的操作数已经压入栈中;执行指令时会将操作数从栈中弹出,是否将操作数再次压入栈中取决与具体的命令。

new,dup指令

使用new关键字创建对象的时候出现的字节码指令,通常伴随着 dup 指令 ,dup指令将复制一份操作数栈顶的值

这里是因为 invokespecial 调用类的构造方法时,将会消耗new的结果引用,如果我们不复制一份 ,那么这个引用就丢掉了。

public class ByteCodeDemo {

    public static void main(String[] args) {

        Object b = new Object();
    }
}

0 new #2 <java/lang/Object>
3 dup
4 invokespecial #1 <java/lang/Object.<init> : ()V>
7 astore_1
8 return

pop 指令

    public static void main(String[] args) throws InterruptedException {
        ByteCodeDemo byteCodeDemo = new ByteCodeDemo();
        byteCodeDemo.methodOne();

    }

    public  String methodOne(){
        return "no";
    }
  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    Code:
       0: new           #2                  // class com/sz/jasyptdemo/ByteCodeDemo
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method methodOne:()Ljava/lang/String;
      12: pop
      13: return

调用了methodOne()方法,这个方法是有返回结果的,但是我们并没有接受 因此JVM会调用 pop指令,将返回值抛弃掉

iconst,bipush,sipush,ldc

iconst 表示加载一个常量,常量的值范围在 -1 ~5 之间,bipush 加载一个字节所能表示的int值,sipush加载两个字节所能表示的int值,ldc 则能加载任意值

    public static void main(String[] args) throws InterruptedException {
        int a = 5;
        int b = 6;
        int c = 129;
        int d = 32768;
    }
         0: iconst_5
         1: istore_1
         2: bipush        6
         4: istore_2
         5: sipush        129
         8: istore_3
         9: ldc           #2                  // int 32768
        11: istore        4
        13: return

《深入理解Java虚拟机》 JAVA 字节码指令 基础

Throwable

如果抛出异常,会将操作数栈清空,然后将异常实例压入操作数栈

2. 局部变量表 (数组)

加载与存储 load,store

Java 方法栈桢的另外一个重要组成部分则是局部变量区,字节码程序可以将计算的结果缓存在局部变量区之中。

Java 虚拟机将局部变量区当成一个数组,如果是实例方法,那么局部变量表这个数组的0号下标位置就是就是this指针,1号下标位置就是 参数,后面依次存放局部变量。

    public static void main(String[] args) throws InterruptedException {
        ByteCodeDemo byteCodeDemo = new ByteCodeDemo();
        byteCodeDemo.method(3);
    }

    public void method(int i){
        int a = 5;
        int b = 6;
        int c = 129;
        int d = 32768;
    }

对应的局部变量表

《深入理解Java虚拟机》 JAVA 字节码指令 基础

因为调用的是实例方法,所以本地变量表序号0的位置上是 this指针,1号上是 方法参数 i,后面依次是方法从上往下的局部变量。

JVM对局部变量的主要有两组命令 加载 命令 load, 存储命令 sotre

   public static void main(String[] args) throws InterruptedException {
        ByteCodeDemo byteCodeDemo = new ByteCodeDemo();
        byteCodeDemo.method(3);
    }

    public void method(int i){
        int a = 5;
        int b = 6;
        int c = 129;
        int d = 32768;

        if (d<300){
            System.out.println("...");
        }
    }
 0 iconst_5
 1 istore_2
 2 bipush 6
 4 istore_3
 5 sipush 129
 8 istore 4
10 ldc #5 <32768>
12 istore 5
14 iload 5
16 sipush 300
19 if_icmpge 30 (+11)
22 getstatic #6 <java/lang/System.out : Ljava/io/PrintStream;>
25 ldc #7 <...>
27 invokevirtual #8 <java/io/PrintStream.println : (Ljava/lang/String;)V>
30 return

如上的字节码指令所示,首先是加载常量5到栈顶,然后调用 istore 将栈顶元素存储到局部变量表下标为2的位置上;然后调用bispush,将6压到栈顶… 然后调用iload指令 加载局部变量表下标为5的内容,与栈顶元素 300 比较,如果满足条件,往下执行;如果不满足,跳到偏移量为30的地方执行return返回;

不同基本数据的类型,有不同的load和store命令,如下图所示

《深入理解Java虚拟机》 JAVA 字节码指令 基础

通常对局部变量的操作是首先加载值然后压到操作数栈中进行计算,如下所示

    public void method(int i){
        int a = 5;
        int b = a+10;
        int c = 129;
        int d = 32768;


        if (d<300){
            System.out.println("...");
        }
    }
 0 iconst_5
 1 istore_2
 2 iload_2
 3 bipush 10
 5 iadd
 6 istore_3
 7 sipush 129
10 istore 4
12 ldc #5 <32768>
14 istore 5
16 iload 5
18 sipush 300
21 if_icmpge 32 (+11)
24 getstatic #6 <java/lang/System.out : Ljava/io/PrintStream;>
27 ldc #7 <...>
29 invokevirtual #8 <java/io/PrintStream.println : (Ljava/lang/String;)V>
32 return

如第2,3,5行指令所示;

但是也有指令能直接对局部变量表上的数值进行运算: 自增,自减操作

直接操作局部变量表的指令 iinc

    public void method(int i){
        int a = 1;
        int b = 10;

        a++;
        b--;
    }
 0 iconst_1
 1 istore_2
 2 bipush 10
 4 istore_3
 5 iinc 2 by 1
 8 iinc 3 by -1
11 return

如上字节码所示 iinc + 局部变量表的下标 + by + 增加的值

3. 其他指令

instanceof

后跟目标类,判断栈顶元素是否为目标类 / 接口的实例。是则压入 1,否则压入 0

    public void method(int i){
        Date date = new Date();
        if (date instanceof Object) {
            System.out.println("ofcause");
        }
    }
 0 new #5 <java/util/Date>
 3 dup
 4 invokespecial #6 <java/util/Date.<init> : ()V>
 7 astore_2
 8 aload_2
 9 instanceof #7 <java/lang/Object>
12 ifeq 23 (+11)
15 getstatic #8 <java/lang/System.out : Ljava/io/PrintStream;>
18 ldc #9 <ofcause>
20 invokevirtual #10 <java/io/PrintStream.println : (Ljava/lang/String;)V>
23 return

getstatic

访问静态字段,见上

monitorente monitorexit

为栈顶元素加锁和解锁文章来源地址https://www.toymoban.com/news/detail-449734.html

    public void method(int i){
      synchronized (new Object()){
          System.out.println("sync");
      }
    }

 0 new #5 <java/lang/Object>
 3 dup
 4 invokespecial #1 <java/lang/Object.<init> : ()V>
 7 dup
 8 astore_2
 9 monitorenter
10 getstatic #6 <java/lang/System.out : Ljava/io/PrintStream;>
13 ldc #7 <sync>
15 invokevirtual #8 <java/io/PrintStream.println : (Ljava/lang/String;)V>
18 aload_2
19 monitorexit
20 goto 28 (+8)
23 astore_3
24 aload_2
25 monitorexit
26 aload_3
27 athrow
28 return

到了这里,关于《深入理解Java虚拟机》 JAVA 字节码指令 基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入理解Java虚拟机(读书笔记)

    JCP:Java Community Process(Java社区) JSR:Java Specification Requests(Java规范提案) JEP:JDK Enhancement Proposals(Oracle Java版本管理) JMM:Java Memory Model(Java内存模型) OSR:On-Stack Replacement(栈上替换) TCK:Technology Compatibility Kit(技术兼容性测试工具) AOT:Ahead of Time Compilation(提前编

    2024年02月08日
    浏览(72)
  • 《深入理解Java虚拟机》读书笔记:Java内存区域

    Java内存区域包含程序计数器、虚拟机栈、本地方法栈、Java堆、方法区五个区域。 运行时数据区分类   Java内存区域   程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的信号指示器。 字节码解释器工作时就是通过改变这个计数

    2024年02月14日
    浏览(52)
  • 深入理解Java虚拟机(二)Java内存区域与内存溢出异常

            对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出问题,看起来由虚拟机管理内存一切都很美好。不过,也正是因为Java程序员把控制内存的权力交给了Java虚拟机,一旦出

    2024年02月16日
    浏览(72)
  • 《深入理解Java虚拟机》读书笔记:HotSpot虚拟机对象探秘

    基于实用优先的原则,以常用的虚拟机HotSpot和常用的内存区域Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程。以下是本节内容的脑图。   HotSpot虚拟机对象探秘脑图   创建对象大致分为5步:1.检查类是否加载,没有加载先加载类 2.分配内存 3.初始

    2024年02月14日
    浏览(72)
  • 《深入理解Java虚拟机》读书笔记:垃圾收集算法

    由于垃圾收集算法的实现涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,因此本节不打算过多地讨论算法的实现,只是介绍几种算法的思想及其发展过程。 垃圾收集算法概要   标记-清除算法最基础的收集算法是“标记-清除”(Mark-Sweep)算法,算

    2024年02月13日
    浏览(67)
  • 《深入理解Java虚拟机》读书笔记: 类加载器

                                                             类加载器     虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现

    2024年02月11日
    浏览(43)
  • 深入理解Java虚拟机——内存分配与回收策略

    在读这篇博客之前,你需要了解分代收集理论中,收集器应该将Java堆划分出不同的区域**,**然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。 例如 appel式回收 ,HotSpot虚拟机中的新生代收集器都采用了appel式回收来设计新生代内

    2024年02月04日
    浏览(47)
  • 《深入理解Java虚拟机》读书笔记:内存分配策略

    Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象的内存。关于回收内存这一点,我们已经使用了大量篇幅去介绍虚拟机中的垃圾收集器体系以及运作原理,现在我们再一起来探讨一下给对象分配内存的那点事

    2024年02月13日
    浏览(56)
  • 《深入理解Java虚拟机》读书笔记:垃圾收集器

    垃圾收集器   HotSpot虚拟机包含的所有收集器如图3-5所示。图3-5展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。 新生代收集器:Serial、ParNew、Parallel Scavenge,新生代收集器均采用复制算法 老年代收集器:Serial Old(标记-整理算法

    2024年02月13日
    浏览(75)
  • 《深入理解Java虚拟机》读书笔记:判断对象是否存活

    本节内容的概要如下; 对象已死吗?   给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。 客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在

    2024年02月14日
    浏览(94)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包