2012-02-09 65 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); 
    } 
    } 

玩得開心:)