2014-02-22 61 views
4

javac或JIT是否優化不必要的自動裝箱?假設我們有這段代碼。JVM是否優化了不必要的自動裝箱?

for(int i=0; i<100000; i++) { 
    f(i); 
} 

void f(Integer i) { 
    System.out.println(i); 
} 

這段代碼如何得到優化?我猜f將內聯,但不必要的拳擊int(它不會被修改,永遠不會是null)。我們假設該方法不是從任何其他代碼片段調用的。如果方法簽名是
void f(final Integer i)會有什麼區別?

回答

2

JVM可以自由地做任何它喜歡的優化,所以有可能某些JVM會優化它。

這是不好的做法,假設它會,但是對於每個JVM來說,可能有幾個不這樣做。

只要改變方法,因爲它使用它裏面接受拳擊同級別的類型..

+0

嗯,這是我在技術面試中遇到的一個問題,詢問的人相當期待具體的答案。我們在談論HotSpot JVM。我理解你的觀點並同意。 – Sebastian

1

當你看看這個:

public class a 
{ 
    public static void main(String[] args) 
    { 
     for (int i = 0; i < 100000; i++) 
      f(i); 
    } 

    public static void f(Integer i) 
    { 
     System.out.println(i); 
    } 
} 

,看看它是什麼樣子調用javac a.java && javap -c a後,你會得到

Compiled from "a.java" 
public class a { 
    public a(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_0  
     1: istore_1  
     2: iload_1  
     3: ldc   #2     // int 100000 
     5: if_icmpge  21 
     8: iload_1  
     9: invokestatic #3     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
     12: invokestatic #4     // Method f:(Ljava/lang/Integer;)V 
     15: iinc   1, 1 
     18: goto   2 
     21: return   

    public static void f(java.lang.Integer); 
    Code: 
     0: getstatic  #5     // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: aload_0  
     4: invokevirtual #6     // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
     7: return   
} 

此字節碼告訴我們Integer.valueOf()被稱爲(main 9:),因此沒有優化德在這種情況下,在編譯級別。然而,正如@Tim B指出的那樣,JVM內發生的事情是另一個無法預測的問題。最好假定最壞的情況 - JVM不會優化它。

+6

'javac'幾乎沒有進行優化,讀取字節碼並不能很好地測試代碼在優化時的功能。 –

4

在OpenJDK和熱點JVM 5 - 8不優化他們離開,除非他們不使用(即使在當時並不總是)

然而,有透視感,當你問這些是非常重要的問題或回答他們。與將數字轉換爲String的代碼(無論如何,JVM執行此操作的方式)相比,Autoboixing是微不足道的,與寫入控制檯相比,這是微不足道的。如果取出System.out.println(),這將節省99.99%的時間,所以在這裏擔心自動裝箱會擔心錯誤的事情。

在您的具體情況中,由於PrintStream.println(Object)被調用,因此無法優化自動裝箱方式。 JVM通常不理解庫所做的事情,也不能假定調用PrintStream.println(int)會做同樣的事情。

+0

那麼記憶效率呢?如果在每次調用自動裝箱發生時都會有大約99873(100000-127)個Integer實例被不必要地創建。我不同意我不應該擔心自動裝箱。但是我現在看到爲什麼這種情況不會被優化,因爲println(Object)的調用。 – Sebastian

+2

@Sebastian是正確的,我並不是說它什麼都不做,只是轉換爲文本的成本要高得多,寫入屏幕的成本遠高於此。嘗試計算取出整數所取得的效果與取出整體所取得的結果之間的差異。你不需要測量它,差別非常大,你會看到差異。 –