Java Bytecode "exzessive" Anzahl von dup als "schlechten" Code betrachtet?

8

Das ist eine zweiteilige Frage, würde aber bei den einzelnen Stücken keinen Sinn ergeben. Ist eine große Anzahl von dup Anweisungen innerhalb der Bytecode-Ausgabe ein Indikator für schlecht geschriebenen Code? Wo groß ist definiert durch einen Prozentsatz aller Bytecode-Anweisungen. Wie geht man weiter mit dem Umschreiben von Code, der eine dup Anweisung generiert?

    
Woot4Moo 15.02.2013, 20:06
quelle

3 Antworten

7

Sprechen wir über javac output, das Sie analysieren, oder Ihren eigenen Compiler / Generator? Wenn Sie über die Qualität Ihres Java-Codes aus der Perspektive dessen, was javac produziert, beunruhigt sind - vergessen Sie es. Zuallererst erzeugt javac einen suboptimalen Bytecode und stützt sich auf JVM / JIT, um alle Optimierungen durchzuführen (sehr gute Wahl). Aber Bytecode ist immer noch viel besser als alles, was man schnell finden kann. Es ähnelt der Frage nach der Qualität des Assembler-Codes, der vom C-Compiler generiert wird.

Wenn Sie selbst Bytecode generieren, kann eine übermäßige Anzahl von dup schlecht aussehen, aber es kann auch nicht irgendwelche Auswirkungen auf die Leistung haben. Denken Sie daran, dass der Bytecode in die Assembly auf dem Zielrechner übersetzt wird. JVM ist eine Stapelmaschine, aber die meisten Architekturen sind heutzutage registerbasiert. Die Tatsache, dass dup verwendet wird, liegt nur daran, dass einige Bytecode-Anweisungen destruktiv sind (Pop-Wert vom Operandenstapel beim Lesen). Dies geschieht nicht mit Registern - Sie können sie beliebig oft lesen. Nehmen Sie den folgenden Code als Beispiel:

%Vor%

dup muss hier verwendet werden, da invokespecial oben im Operandenstapel erscheint. Ein Objekt zu erstellen, das nach dem Aufruf von Konstruktor einen Verweis darauf verliert, klingt wie eine schlechte Idee. Aber in Assembly gibt es keine dup , kein Kopieren und Duplizieren von Daten. Sie werden nur eine einzige CPU-Registrierung haben, die auf java/lang/Object zeigt.

Mit anderen Worten, suboptimaler Bytecode wird im laufenden Betrieb in "optimalere" Assemblierung übersetzt. Nur ... nicht stören.

    
Tomasz Nurkiewicz 15.02.2013 20:13
quelle
2

Der Befehl dup dupliziert einfach das oberste Element des Operandenstapels. Wenn der Compiler weiß, dass er einen Wert mehrmals innerhalb eines relativ kurzen Zeitraums verwenden wird, kann er auswählen, den Wert zu duplizieren und auf dem Operandenstapel zu halten, bis er benötigt wird.

Einer der häufigsten Fälle, in denen Sie dup sehen, ist, wenn Sie ein Objekt erstellen und es in einer Variablen speichern:

%Vor%

Running javap -c , Sie erhalten den folgenden Bytecode:

%Vor%

Auf Englisch: Die Operation new erstellt eine neue Instanz des Objekts Foo und die invokespecial den Konstruktor Foo . Da Sie den Verweis auf dem Stack benötigen, um den Konstruktor aufzurufen und auch in der Variable zu speichern, ist es sehr sinnvoll, dup zu verwenden (besonders, da die Alternative, in der Variablen zu speichern und anschließend den ctor aufzurufen, könnte verletzen das Java-Speichermodell).

Hier ist ein Fall, in dem der Oracle Java Compiler (1.6) dup nicht verwendet hat, wenn ich es erwarten würde:

%Vor%

Ich würde erwarten, dass der Compiler dup den Wert von x hat, da er mehrmals im Ausdruck erscheint. Stattdessen wurde ein Code hinzugefügt, der den Wert wiederholt aus dem Objekt geladen hat:

%Vor%

Ich hätte die dup erwartet, weil es relativ teuer ist, einen Wert von einem Objekt abzurufen (selbst nachdem Hotspot seine Magie entfaltet hat), während sich zwei Stapelzellen wahrscheinlich auf der gleichen Cache-Zeile befinden.

    
parsifal 15.02.2013 20:53
quelle
1

Wenn Sie sich Sorgen machen über den Einfluss von dup und dessen Beziehungen auf die Leistung, machen Sie sich keine Sorgen. Die JVM tut gerade rechtzeitig Kompilierung, also sollte es wirklich keinen Unterschied in der Leistung machen.

Was die Qualität des Codes angeht, gibt es zwei Hauptursachen, die dazu führen, dass Javac dup -Anweisungen generiert. Die erste ist die Instanziierung von Objekten, wo sie unvermeidlich ist. Die zweite ist bestimmte Verwendungen von unmittelbaren Werten in Ausdrücken. Wenn Sie eine Menge später sehen, könnte es schlechter Code sein, da Sie normalerweise solche komplizierten Ausdrücke in Ihrem Quellcode nicht wollen (es ist weniger lesbar).

Die anderen Versionen von dup ( dup_x1 , dup_x2 , dup2 , dup2_x1 und dup2_x2 ) sind besonders problematisch, da die Objekt-Instanziierung diese nicht verwendet später. Natürlich ist es auch dann kein großes Problem. Es bedeutet nur, dass der Quellcode nicht so lesbar ist, wie er sein könnte.

Wenn der Code nicht aus Java kompiliert wird, sind alle Wetten deaktiviert. Das Vorhandensein oder Nichtvorhandensein von Anweisungen sagt dir nicht viel, besonders in den Sprachen, deren Compiler die Kompilierzeit optimieren.

    
Antimony 15.02.2013 21:14
quelle