精华内容
下载资源
问答
  • java虚拟机指令dup详解发布时间:2020-09-11 15:24:12来源:脚本之家阅读:98作者:CLAYJJ本文实例为大家介绍了java虚拟机指令dup,供大家参考,具体内容如下举个例子:public class ExceptionTest{void cantBeZero...

    java虚拟机指令dup详解

    发布时间:2020-09-11 15:24:12

    来源:脚本之家

    阅读:98

    作者:CLAYJJ

    本文实例为大家介绍了java虚拟机指令dup,供大家参考,具体内容如下

    举个例子:

    public class ExceptionTest{

    void cantBeZero(int i) throws Exception{

    throw new Exception();

    }

    }

    上面代码编译后的字节码指令如下:

    void cantBeZero(int) throws java.lang.Exception;

    descriptor: (I)V

    flags:

    Code:

    stack=2, locals=2, args_size=2

    0: iload_1

    1: ifne 12

    4: new #2

    // class java/lang/Exception

    7: dup

    8: invokespecial #3

    // Method java/lang/Exception."":()V

    11: athrow

    12: return

    1) 其中new指令在java堆上为Exception对象分配内存空间,并将地址压入操作数栈顶;

    2) 然后dup指令为复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址;

    3) invokespecial指令调用实例初始化方法:()V,注意这个方法是一个实例方法,所以需要从操作数栈顶弹出一个this引用,也就是说这一步会弹出一个之前入栈的对象地址;

    4) athrow指令从操作数栈顶取出一个引用类型的值,并抛出;

    5) 最后由return指令结束方法。

    从上面的五个步骤中可以看出,需要从栈顶弹出两个实例对象的引用,这就是为什么会在new指令下面有一个dup指令,其实对于每一个new指令来说一般编译器都会在其下面生成

    一个dup指令,这是因为实例的初始化方法肯定需要用到一次,然后第二个留给程序员使用,例如给变量赋值,抛出异常等,如果我们不用,那编译器也会生成dup指令,在初始化方法调用完成后再从栈顶pop出来。例如我们仅仅创建一个对象而不做任何操作,例如:

    void cantBeZero(int i) throws Exception{

    new Exception();

    }

    上面的代码仅仅创建了一个Exception对象,而没有做任何操作。

    其编译后的字节码指令如下:

    void cantBeZero(int) throws java.lang.Exception;

    descriptor: (I)V

    flags:

    Code:

    stack=2, locals=2, args_size=2

    0: new #2 // class java/lang/Exception

    3: dup

    4: invokespecial #3 // Method java/lang/Exception."":()V

    7: pop

    8: return

    也会生成一个dup指令,只不过在调用完实例初始化方法后,将重复的实例引用又pop出栈了。不过这种情况基本不会出现在我们的代码中,因为我们创建的每一个对象都应该是有用的。

    通过上面的例子你应该比较清楚的理解了为什么创建对象时总会有一个dup指令了。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。

    展开全文
  • java虚拟机指令dup详解

    2020-08-29 02:08:04
    主要为大家详细介绍了java虚拟机指令dup,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Java虚拟机指令dup

    2020-08-14 15:51:18
    dup指令的作用:dup指令可以复制操作数栈栈顶的一个字,再将这个字压入栈。也就是对栈顶的内容做了个拷贝,此时操作数栈上有连续相同的两个对象地址。 JAVA是基于栈的实现,任何操作都是入栈出栈,没有任何寄存器,...

    转载自:https://blog.csdn.net/Gabriel576282253/article/details/98968241

    dup指令的作用:dup指令可以复制操作数栈栈顶的一个字,再将这个字压入栈。也就是对栈顶的内容做了个拷贝,此时操作数栈上有连续相同的两个对象地址。

    JAVA是基于栈的实现,任何操作都是入栈出栈,没有任何寄存器,所以如果要对某一操作数做两次连续操作,那就要复制两次栈顶操作数,比如:

       public void test() {
            int x;
            int y = x = 2;
        }
    

    当常数2被压入栈顶后,它要连续两次store到变量x和y,所以这里编译后肯定有一个dup操作,javac、javap -v 后的执行结果:

      public void test();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=3, args_size=1
             0: iconst_2
             1: dup
             2: istore_1
             3: istore_2
             4: return
    

    如果不做dup操作,那么istore_1将20存到内存中的x后,再istore_2要么没有操作数,要么是一个其它的操作数。这在编译时对连续操作已经做dup操作了,所以不会出现这个情况。


    那么new 指令后,为什么一定要dup操作呢?
    因为java代码的new操作编译为虚拟机指令后,虚拟机指令new在堆上分配了内存并在栈顶压入了指向这段内存的地址供任何下面的操作来调用,但是在这个操作数被程序员能访问的操作之前,虚拟机自己肯定要调用对象的 方法,也就是如果程序员做一个 Object o = new Object(); 其实要连续两次对栈顶的操作数进行操作。其中一次是虚拟机内部自动调用的,另一次才是程序员的访问,例如给变量赋值,抛出异常等。

        public void get() {
            Object o = new Object();
        }
    

    字节码如下:

     public void get();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=2, args_size=1
             0: new           #2                  // class java/lang/Object
             3: dup
             4: invokespecial #1                  // Method java/lang/Object."<init>":()V
             7: astore_1
             8: return
    
    1. 其中new指令在java堆上为 Object 对象分配内存空间,并将地址压入操作数栈顶;
    2. 然后dup指令为复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址;
    3. invokespecial指令调用实例初始化方法<init>:()V,注意这个方法是一个实例方法,所以需要从操作数栈顶弹出一个Object对象的引用,作为传给构造器的“this”参数, 也就是说这一步会弹出一个之前入栈的对象地址;(让invokespecial命令知道这个构造方法是刚才创建的那个引用的)
    4. astore_1 指令从操作数栈顶取出 Object 对象的引用并存到局部变量表;
    5. 最后由return指令结束方法。
    展开全文
  • 2 descriptor: (I)V3 flags:4 Code:5 stack=2, locals=2, args_size=2 6 0: iload_17 1: ifne 12 8 4: new #2 //class java/lang/Exception 9 7: dup10 8: invokespecial #3 //Method java/lang/Exception."":()V 11...

    举个例子:

    1 public classExceptionTest{2

    3 void cantBeZero(int i) throwsException{4 throw newException();5

    6 }7

    8 }

    上面代码编译后的字节码指令如下:

    1 void cantBeZero(int) throwsjava.lang.Exception;2 descriptor: (I)V3 flags:4 Code:5 stack=2, locals=2, args_size=2

    6 0: iload_17 1: ifne 12

    8 4: new #2 //class java/lang/Exception

    9 7: dup10 8: invokespecial #3 //Method java/lang/Exception."":()V

    11 11: athrow12 12: return

    1) 其中new指令在java堆上为Exception对象分配内存空间,并将地址压入操作数栈顶;

    2) 然后dup指令为复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址;

    3) invokespecial指令调用实例初始化方法:()V,注意这个方法是一个实例方法,所以需要从操作数栈顶弹出一个this引用,也就是说这一步会弹出一个之前入栈的对象地址;

    4) athrow指令从操作数栈顶取出一个引用类型的值,并抛出;

    5) 最后由return指令结束方法。

    从上面的五个步骤中可以看出,需要从栈顶弹出两个实例对象的引用,这就是为什么会在new指令下面有一个dup指令,其实对于每一个new指令来说一般编译器都会在其下面生成

    一个dup指令,这是因为实例的初始化方法肯定需要用到一次,然后第二个留给程序员使用,例如给变量赋值,抛出异常等,如果我们不用,那编译器也会生成dup指令,在初始化方法调用完成后再从栈顶pop出来。例如我们仅仅创建一个对象而不做任何操作,例如:

    1 void cantBeZero(int i) throwsException{2 newException();3

    4 }

    上面的代码仅仅创建了一个Exception对象,而没有做任何操作。

    其编译后的字节码指令如下:

    1 void cantBeZero(int) throwsjava.lang.Exception;2 descriptor: (I)V3 flags:4 Code:5 stack=2, locals=2, args_size=2

    6 0: new #2 //class java/lang/Exception

    7 3: dup8 4: invokespecial #3 //Method java/lang/Exception."":()V

    9 7: pop10 8: return

    也会生成一个dup指令,只不过在调用完实例初始化方法后,将重复的实例引用又pop出栈了。不过这种情况基本不会出现在我们的代码中,因为我们创建的每一个对象都应该是有用的。

    通过上面的例子你应该比较清楚的理解了为什么创建对象时总会有一个dup指令了。

    展开全文
  • java虚拟机指令dup的理解

    千次阅读 2019-08-09 18:05:40
    dup指令的作用:dup指令可以复制操作数栈栈顶的一个字,再将这个字压入栈。也就是对栈顶的内容做了个备份,此时操作数栈上有连续相同的两个对象地址。 大家知道,JAVA/CLR是完全基于栈的实现,任何操作都是入栈出栈...

    参考:https://www.cnblogs.com/CLAYJJ/p/7698035.html

     

    dup指令的作用:dup指令可以复制操作数栈栈顶的一个字,再将这个字压入栈。也就是对栈顶的内容做了个备份,此时操作数栈上有连续相同的两个对象地址。

    大家知道,JAVA/CLR是完全基于栈的实现,任何操作都是入栈出栈,没有任何寄存器,所以如果要对某一操作数做两次连续操作,那就要复制两次栈顶操作数,比如:
    int x;
    int y = x = 2;

    public class DupTest2 {
        public static void main(String[] args) {
            int x;
            int y = x = 2;
        }
    }

    当常数2被压入栈顶后,它要连续两次store到变量x和y,所以这里编译后肯定有一个dup操作,如下图所示:


    如果不做dup操作,那么istore_1将20存到内存中的x后,再istore_2要么没有操作数,要么是一个其它的操作数。
    当然这在编译时对连续操作已经做dup操作了,所以不会真的出现这个情况。


    那么new 指令后,为什么一定要dup操作呢?
    因为java代码的new操作编译为虚拟机指令后,虚拟机指令new在堆上分配了内存并在栈顶压入了指向这段内存的地址供任何下面的操作来调用,但是在这个操作数被程序员能访问的操作之前,虚拟机自己肯定要调用对象的 <init> 方法,也就是如果程序员做一个 Type a = new Type(); 其实要连续两次对栈顶的操作数进行操作。其中一次是虚拟机内部自动调用的,另一次才是程序员的访问,例如给变量赋值,抛出异常等。

    测试代码:

    public class DupTest {
    
        public void test() {
            DupTest dt = new DupTest();
        }
    }

    反编译结果:

     

    1) 其中new指令在java堆上为 DupTest 对象分配内存空间,并将地址压入操作数栈顶;

    2) 然后dup指令为复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址;

    3) invokespecial指令调用实例初始化方法<init>:()V,注意这个方法是一个实例方法,所以需要从操作数栈顶弹出一个DupTest 对象的引用,也就是说这一步会弹出一个之前入栈的对象地址;

    4) astore_1 指令从操作数栈顶取出 DupTest 对象的引用并存到局部变量表;

    5) 最后由return指令结束方法。

    从上面的五个步骤中可以看出,需要从栈顶弹出两个实例对象的引用

     

    抛出异常的示例:

    public class ExceptionTest{
    
        void cantBeZero(int i) throws Exception{
            throw new Exception();
        }
    }

    反编译结果:

    1) 其中new指令在java堆上为Exception对象分配内存空间,并将地址压入操作数栈顶;

    2) 然后dup指令为复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址;

    3) invokespecial指令调用实例初始化方法<init>:()V,注意这个方法是一个实例方法,所以需要从操作数栈顶弹出一个this引用,也就是说这一步会弹出一个之前入栈的对象地址;

    4) athrow指令从操作数栈顶取出一个引用类型的值,并抛出;

     

    这种情况是99%以上存在的,而java 编译器是一种聪明的编译器,所以只要有 new 操作就优化为将对象的地址操作数DUP,第一次调用invokespecial <init>时会弹出一个,下面一个留给对该对象访问的操作,即使你的代码是:new Type();没有任何引用,有些虚拟机也会先 dup(不同版本编译结果不同),然后<init>时弹出一个操作数,后面会立即pop掉被复制的那个操作数。这样的做目的是为了编译优化。代码和反编译结果如下:

    测试代码:

    public class DupTest {
    
        public void test() {
            new DupTest();
        }
    }

     

    反编译结果:

    可以看到,在仅仅调用了 new DupTest() 的情况下,java编译器仍然生成了一条 dup 指令,紧接着虚拟机调用了 <init> 方法,然后立即一条 pop 指令弹出了那个被复制的操作数。

     

    有人说那可以直接从栈顶先store到内存中,需要操作的时候再load到栈顶啊,注意在没有<init>操作之前,这个对象对于程序员是不可见的,否则就会访问到残废的对象,所以只能是先<init>然后才能store到内存中。这两步操作的操作数必须都直接是原来已经存在栈中的,所以只能是dup。
     

    展开全文
  • 对象实例化 在实例化对象的过程中,JVM发生了什么化学反应? (1)下面从最简单的 Object ref = new Object(); 进行分析,查看字节码...18: new #8 // class java/lang/Object 21: dup 22: invokespecial #9 ...
  • 在看《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)》这本书时,有几处的字节码在new之后会紧接着出现dup指令,我么以书中253页的字节码为例,说明dup指令的作用。 其中Java代码为: public class Dynamic...
  • 深入JAVA虚拟机指令>>这本书也没有任何说明. 我们先来看看为dup指令的作用,dup指令可以复制栈顶的一个字再压入栈,也就是把栈顶的内容做个备份. 大家知道,JAVA/CLR是完全基于栈的实现,任何操作都是入栈出栈,...
  • 创建一个普通对象,类似执行A a=new A()这条语句,通过反编译javap -c可以得到对应指令如下 ...3: dup 4: invokespecial #3 // Method main/proxy/A."&lt;init&gt;":()V 复制...
  • Java JVM-虚拟机专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Java JVM-虚拟机 为什么 new 指令后执行 dup 指令? 关于字节码相关问题,可参考本专栏相关文章。在此不做介绍,直接进行分析。 在做字节码...
  • jvm dup

    千次阅读 2017-01-23 20:13:15
    为什么对象被new 以后在执行dup操作? 今天有个朋友问我,为什么一个new一...搜索引擎都找不到答案,包括翻了Java虚拟机指令>>这本书也没有任何说明. 我们先来看看为dup指令的作用,dup指令可以复制栈顶的一个字再压入栈
  • 为什么对象被new 以后在执行dup操作? 今天有个朋友问我,为什么一个new一...深入JAVA虚拟机指令>>这本书也没有任何说明. 我们先来看看为dup指令的作用,dup指令可以复制栈顶的一个字再压入栈,也就是把栈顶的内容...
  • 本文参考Java虚拟机规范(第9版).下图是数据类型的分类,根据大小分成了两类,没必要全部去记忆,只需要记住类别2的两个内容就好了,long和double单独一类就是因为他们占用空间太大了,64bit,8各字节。 指令解释没有...
  • java作为一种高级语言,对开发者而言,创建一个对象是非常容易的,原因就是虚拟机底层做了很好的封装,调用者不需要关注太多细节。通过new关键字,就可以创建一个对象。了解对象的创建过程,内存布局对于性能上的...
  • 如同操作一个普通数据结构中的堆栈那样,JVM提供的操作数栈管理指令,可以用于直接操作操作数...Java虚拟机没有提供交换两个64位数据类型( long、doub1e)数值的指令。 指令nop,是一个非常特殊的指令,它的字节码为.
  • 开始用JBE看class文件时,发现new指令后都跟着dup操作,翻了《深入Java虚拟机指令》也没什么结果,Google后转到“诗剑书生”的CSDN专栏,这个问题得到了答案。再顺着下去看其它的博文,有个问题开始给了我危机感。 ...

空空如也

空空如也

1 2
收藏数 27
精华内容 10
关键字:

java虚拟机dup

java 订阅