2012-02-09 36 views
12

我们的项目执行一些Java字节码检测。我们偶然发现了一些奇怪的行为。假设下面的代码片段:Oracle和Eclipse编译器生成的java字节码差异

public void a() { 
    new Integer(2); 
    } 

甲骨文的javac编译以上为以下字节码:

0: new #2; //class java/lang/Integer 
    3: dup 
    4: iconst_2 
    5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V 
    8: pop 
    9: return 

和Eclipse的编译器分为:

0: new #15; //class java/lang/Integer 
    3: iconst_2 
    4: invokespecial #17; //Method java/lang/Integer."<init>":(I)V 
    7: return 

正如你可以看到,甲骨文编译器生成“新”之后的“dup”,而Eclipse不。在这个用例中,这是完全正确的,因为新创建的Integer实例完全不用,所以不需要“dup”。

我的问题是:

  1. 有不同的编译器之间的差异有些概述?文章/博客文章?
  2. 我可以安全地得出结论:如果“新”和“invokespecial”之间没有“dup”,那么在初始化之后不会使用对象?
+4

检测字节码的目标是什么?这种差异是否会对您造成问题?请注意,不能确保Java编译器将生成的字节码是什么。在未来的版本中,完全可能的是,Oracle的'javac'会产生与你现在看到的不同的东西 - 所以编写一个严重依赖于编译器生成的确切字节码的程序并不是一个好主意。 – Jesper 2012-02-09 08:19:06

+0

您是否对Eclipse使用不同的JDK? – Nishant 2012-02-09 08:19:20

回答

3
  1. 我可以有把握地断定,如果有那么对象未初始化之后用“新”和“invokespecial”之间没有“DUP”?

我不知道你的意思究竟,但对创建对象的引用可能的地方由构造存储。因此调用方法在初始化后可能不会使用该对象,但该对象仍然可以访问,因此可能不是垃圾收集。

6

如果有编译后通常使用DUPinvokespecial那么对象之间。例如,现场初始化通常是序列,DUPinvokespecial & putfield。然而,在你的例子中,最后一条指令是pop它清除了堆栈中的objectref--这就是你可以假定这个对象没有被使用的方式。

+0

正如A.H.所指出的,pop只意味着它不被调用者使用。对象本身可以在ctor中提供对自身的引用。 – Antimony 2013-03-30 21:10:14

1

传递引用将打破这一格局有点

public class Bump { 

    Test t; 

    public Bump() { 
     new Test(this); 
    } 
    public void setT(Test t) { 
     this.t = t; 
    } 
    } 

然后一个可以使用这个用于存储结果返回:)

public class Test { 

    Bump b; 

    public Test(Bump b) { 
     this.b = b; 
     b.setT(this); 
    } 
    } 

玩得开心:)