Wie in JEP 280 geschrieben: Zeichenfolgenverkettung angeben :
Ändern Sie die
String
Bytecode-Sequenz für die statische Verkettung, die von generiert wirdjavac
, uminvokedynamic
Aufrufe von JDK-Bibliotheksfunktionen zu verwenden. Dies ermöglicht zukünftige Optimierungen derString
Verkettung, ohne dass weitere Änderungen am von ausgegebenen Bytecode erforderlich sindjavac
.
Hier möchte ich verstehen, wie invokedynamic
Anrufe verwendet werden und wie sich die Bytecode-Verkettung von der unterscheidet invokedynamic
.
java
string
string-concatenation
java-9
invokedynamic
Mohit Tyagi
quelle
quelle
Antworten:
Der "alte" Weg gibt eine Reihe von
StringBuilder
orientierten Operationen aus. Betrachten Sie dieses Programm:Wenn wir das mit JDK 8 oder früher kompilieren und dann
javap -c Example
den Bytecode verwenden, sehen wir ungefähr Folgendes:Wie Sie sehen können, erstellt es ein
StringBuilder
und verwendetappend
. Dies ist bekanntermaßen ziemlich ineffizient, da die Standardkapazität des integrierten PuffersStringBuilder
nur 16 Zeichen beträgt und der Compiler nicht wissen kann, ob er im Voraus mehr zuweisen muss, sodass er letztendlich neu zuweisen muss. Es ist auch eine Reihe von Methodenaufrufen. (Beachten Sie, dass die JVM diese Anrufmuster manchmal erkennen und neu schreiben kann, um sie jedoch effizienter zu gestalten.)Schauen wir uns an, was Java 9 generiert:
Oh mein Gott, aber das ist kürzer. :-) Es macht einen einzigen Anruf
makeConcatWithConstants
vonStringConcatFactory
, was dies in seinem Javadoc sagt:quelle
+=
in seiner for-Schleife verwenden sollte. Ich sagte ihnen, dass es darauf ankommt, aber vergessen wir nicht, dass sie irgendwann einen besseren Weg finden könnten, um Concat zu spielen. Die Schlüsselzeile ist wirklich die vorletzte Zeile:So by being smart, you have caused a performance hit when Java got smarter than you.
invokedynamic
können zur Laufzeit verschiedene Verkettungsstrategien ausgewählt und an den ersten Aufruf gebunden werden, ohne dass der Aufwand für einen Methodenaufruf und eine Versandtabelle bei jedem Aufruf anfällt. mehr in Nicolais Artikel hier und in der JEP .Object
, aber dann müssten Sie alle Primitiven einpacken ... (Was Nicolai übrigens in seinem ausgezeichneten Artikel behandelt)String.concat(String)
Methode, deren Implementierung das Array des resultierenden Strings direkt erstellt . Der Vorteil wird umstritten, wenn wirtoString()
auf beliebige Objekte zurückgreifen müssen . Ebenso muss der Aufrufer beim Aufrufen einer Methode, die ein Array akzeptiert, das Array erstellen und füllen, was den Gesamtnutzen verringert. Aber jetzt ist es irrelevant, da die neue Lösung im Grunde das ist, was Sie in Betracht gezogen haben, außer dass sie keinen Box-Overhead hat, keine Array-Erstellung benötigt und das Backend möglicherweise optimierte Handler für bestimmte Szenarien generiert.Bevor wir auf die Details der
invokedynamic
Implementierung eingehen, die zur Optimierung der String-Verkettung verwendet wird, müssen meiner Meinung nach einige Hintergrundinformationen zu Was ist Invokedynamic und wie verwende ich es?Ich würde wahrscheinlich versuchen, Sie mit den Änderungen, die für die Implementierung der Optimierung der String-Verkettung mitgebracht wurden, durch diese zu führen.
Definieren der Bootstrap - Methode : - Mit Java9, den Bootstrap - Methoden für die
invokedynamic
Aufrufstellen, die String - Verkettung in erster Linie zu unterstützenmakeConcat
undmakeConcatWithConstants
wurden mit der eingeführtenStringConcatFactory
Umsetzung.Die Verwendung von invokedynamic bietet eine Alternative zur Auswahl einer Übersetzungsstrategie bis zur Laufzeit. Die in verwendete Übersetzungsstrategie
StringConcatFactory
ähnelt derLambdaMetafactory
in der vorherigen Java-Version eingeführten. Darüber hinaus besteht eines der in der Frage genannten Ziele des JEP darin, diese Strategien weiter auszudehnen.Angeben von Einträgen für konstante Pools : - Dies sind die zusätzlichen statischen Argumente für die
invokedynamic
Anweisung außer (1)MethodHandles.Lookup
Objekt, das eine Factory zum Erstellen von Methodenhandles im Kontext derinvokedynamic
Anweisung ist, (2) einString
Objekt, der im dynamischen Aufruf erwähnte Methodenname Standort und (3) dasMethodType
Objekt, die aufgelöste Typensignatur des dynamischen Aufrufstandorts.Es sind bereits während der Verknüpfung des Codes verlinkt. Zur Laufzeit wird die Bootstrap-Methode ausgeführt und der eigentliche Code für die Verkettung verknüpft. Der
invokedynamic
Anruf wird mit einem entsprechendeninvokestatic
Anruf neu geschrieben. Dadurch wird die konstante Zeichenfolge aus dem konstanten Pool geladen. Die statischen Argumente der Bootstrap-Methode werden genutzt, um diese und andere Konstanten direkt an den Aufruf der Bootstrap-Methode zu übergeben.Verwenden der aufgerufenen dynamischen Anweisung : - Dies bietet die Möglichkeit für eine verzögerte Verknüpfung, indem die Möglichkeit bereitgestellt wird, das Anrufziel während des ersten Aufrufs einmal zu booten. Die konkrete Idee zur Optimierung besteht darin, den gesamten
StringBuilder.append
Tanz durch einen einfacheninvokedynamic
Aufruf zu ersetzen, derjava.lang.invoke.StringConcatFactory
die Werte akzeptiert, die einer Verkettung bedürfen.Der Vorschlag zur Verkettung von Zeichenfolgen angibt anhand eines Beispiels das Benchmarking der Anwendung mit Java9, bei dem eine ähnliche Methode wie @TJ Crowder kompiliert wird und der Unterschied im Bytecode zwischen den verschiedenen Implementierungen deutlich sichtbar ist.
quelle
Ich werde hier ein paar Details hinzufügen. Der wichtigste Teil ist, dass die Verkettung von Zeichenfolgen eine Laufzeitentscheidung ist und keine Kompilierungsentscheidung mehr . Daher kann es sich ändern, was bedeutet, dass Sie Ihren Code einmal gegen Java-9 kompiliert haben und die zugrunde liegende Implementierung nach Belieben ändern können, ohne dass eine erneute Kompilierung erforderlich ist.
Und der zweite Punkt ist, dass es im Moment Folgendes gibt
6 possible strategies for concatenation of String
:Sie können eine davon über einen Parameter auswählen :
-Djava.lang.invoke.stringConcat
. Beachten Sie, dass diesStringBuilder
immer noch eine Option ist.quelle