2016-02-13 11 views
5

Ich habe eine einfache Klasse für die Zwecke der Veranschaulichung bekam:Warum optimiert der Java-Compiler keine triviale Methode?

public class Test { 

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

    public int test2() { 
     return 200; 
    } 
} 

Der Bytecode vom Compiler (kontrolliertt javap -c Test.class) hergestellt ist folgende:

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 

Warum ist die Optimierung der Compiler nicht die test1 Methode auf den gleichen Bytecode für die test2 Methode produziert? Ich würde erwarten, dass es zumindest die redundante Initialisierung der Variablen result vermeidet, wenn man bedenkt, dass es leicht ist, zu dem Schluss zu kommen, dass der Wert 100 überhaupt nicht verwendet wird.

Ich beobachtete dies mit beiden Eclipse-Compiler und javac.

javac Version: 1.8.0_72, als Teil des JDK zusammen mit Java installiert ist:

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

Die * Java-Sprachspezifikation * benötigt keine Optimierungen wie diese, daher ist es nicht sinnvoll, über den "Compiler" zu sprechen, als gäbe es nur einen. Sie sollten angeben, welchen Compiler Sie verwenden. – ruakh

+5

Die klassische Antwort ist, dass Optimierungen in der JVM (http://stackoverflow.com/questions/5981460/optimization-by-javacompiler) – wero

+0

@ruakh Gute Bemerkung gemacht werden; Compiler Informationen hinzugefügt. –

Antwort

4

Eine typische Java Virtual Machine optimiert Ihr Programm zur Laufzeit, nicht während der Kompilierung. Zur Laufzeit weiß die JVM viel mehr über Ihre Anwendung, sowohl über das tatsächliche Verhalten Ihres Programms als auch über die tatsächliche Hardware, auf der Ihr Programm ausgeführt wird.

Der Byte-Code ist lediglich eine Beschreibung, wie sich Ihr Programm verhalten soll. Die Laufzeitumgebung kann beliebige Optimierung auf Ihren Byte-Code anwenden.

Natürlich kann argumentiert werden, dass solche trivialen Optimierungen auch während der Kompilierung angewendet werden können, aber im Allgemeinen ist es sinnvoll, Optimierungen nicht über mehrere Schritte zu verteilen. Jede Optimierung verursacht effektiv eine Unmenge von Informationen über das ursprüngliche Programm und dies kann andere Optimierungen unmöglich machen. Das heißt, nicht alle "besten Optimierungen" sind immer offensichtlich. Ein einfacher Ansatz besteht darin, (fast) alle Optimierungen während der Kompilierung zu löschen und sie stattdessen zur Laufzeit anzuwenden.

+0

ja - zumindest die Information der Zeilennummer würde verloren gehen, so dass Stacktrace nicht korrekt ist; und das Debuggen wird schwieriger sein. – ZhongYu

4

JVM optimiert den Bytecode, was ein Code Cache genannt zu schaffen. Im Gegensatz zu C++ kann JVM viele Daten über Ihr Programm sammeln, zB Wie heiß ist das für die Schleife?, Ist dieser Codeblock überhaupt noch zu optimieren? usw. Die Optimierung hier ist sehr nützlich und führt oft zu besseren Ergebnissen.

Wenn Sie optimieren, wenn sie von Java-Bytecode (dh, wenn Sie Javac nennen) zu übersetzen, Ihr Code könnte für Ihren Computer optimal sein, aber nicht für einige andere Plattform. Es macht also keinen Sinn, hier zu optimieren.

Als Beispiel, nehmen Sie an, dass Ihr Programm AES-Verschlüsselung verwendet. Moderne CPUs haben AES-spezifische Befehlssätze, mit spezieller Hardware, um die Verschlüsselung viel schneller zu machen.

Wenn Javac bei der Kompilierung zu optimieren versucht, dann wird es entweder

  • optimize die Anweisungen auf einer Software-Ebene, wobei in diesem Fall werden Sie nicht profitieren von modernen CPUs programmieren, oder,
  • ersetzen Ihre AES-Anweisungen mit äquivalenten CPU-AES-Anweisungen, die nur auf neuen CPUs unterstützt werden, wodurch Ihre Kompatibilität beeinträchtigt wird.

Wenn stattdessen Javac läßt sie wie in der byptcode ist, dann ist die JVM auf neueren CPUs ausgeführt wird, kann sie als AES erkennen und diese CPU-Fähigkeit ausnutzen, während JVMs auf älteren CPUs laufen, kann sie bei einer Software-Ebene optimiert zur Laufzeit (Code-Cache), geben Sie sowohl Optimalität und Kompatibilität.

Verwandte Themen