2016-02-13 65 views
5

我有一個簡單的類用於說明目的:爲什麼Java編譯器沒有優化一個簡單的方法?

public class Test { 

    public int test1() { 
     int result = 100; 
     result = 200; 
     return result; 
    } 

    public int test2() { 
     return 200; 
    } 
} 

由編譯器(由javap -c Test.class檢驗)所產生的字節碼如下:

public int test1(); 
Code: 
    0: bipush  100 
    2: istore_1 
    3: sipush  200 
    6: istore_1 
    7: iload_1 
    8: ireturn 

public int test2(); 
Code: 
    0: sipush  200 
    3: ireturn 

爲什麼不編譯器優化test1方法生成的相同字節碼爲test2方法?我認爲它至少可以避免result變量的冗餘初始化,因爲很容易得出結論:根本沒有使用100的值。

我用Eclipse編譯器和javac都觀察到了這一點。

javac版本:1.8.0_72,作爲JDK的一部分的Java一起安裝:

Java(TM) SE Runtime Environment (build 1.8.0_72-b15) 
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode) 
+6

* Java語言規範*不需要像這樣的任何優化,所以說「編譯器」就好像只有一個是沒有意義的。你應該指出你正在使用的編譯器。 – ruakh

+5

經典答案是優化在JVM中完成(http://stackoverflow.com/questions/5981460/optimization-by-java-compiler) – wero

+0

@ruakh好評;添加編譯器信息。 –

回答

4

典型的Java虛擬機在運行時優化你的程序,而不是在編譯過程中。在運行時,JVM知道更多關於應用程序的信息,包括程序的實際行爲以及程序執行的實際硬件。

字節碼僅僅是你的程序應該如何表現的描述。運行時可以自由地將任何優化應用於您的字節碼。

當然,人們可以爭辯說,即使在編譯過程中也可以應用這種微不足道的優化,但總的來說,在幾個步驟中不分配優化是有意義的。任何優化都會導致有關原始程序的信息鬆散,這可能使其他優化成爲不可能。這就是說,並不是所有的「最佳優化」都是顯而易見的。一個簡單的方法是在編譯期間簡單地放棄(幾乎)所有優化,並在運行時應用它們。

+0

是的 - 至少行號信息會丟失,所以堆棧跟蹤不準確;並且調試將會更加困難。 – ZhongYu

4

優化JVM字節碼,產生一種叫做代碼緩存。與C++不同,JVM可以收集大量有關程序的數據,例如,循環的熱度如何?,這個代碼塊甚至值得優化嗎?等等。所以這裏優化是非常有用的,並且通常會產生更好的結果。

如果您優化從Java翻譯時字節碼(即,當你調用的javac),你的代碼可能是最適合你的電腦,但不能用於一些不同的平臺。所以在這裏優化是沒有意義的。

舉一個例子,假設你的程序使用AES加密。現代CPU具有特定於AES的指令集,使用特殊硬件可以使加密速度提高很多。

如果javac的試圖在編譯時進行優化,那麼它要麼

  • 優化的軟件級別的指示,在這種情況下,你從現代CPU的編程習慣的好處,或者
  • 更換您的AES指令具有等效的CPU-AES指令,僅在新CPU上支持,這會降低您的兼容性。

相反,如果javac的使他們爲在byptcode,那麼JVM上較新的CPU上運行同樣可以識別它們AES和利用此CPU的能力,而在舊的CPU運行的JVM可以在軟件層面優化他們在運行時(代碼緩存),給你最優性兼容性

相關問題