[JAVA] AppCDS @ OpenJDK

OpenJDK und AppCDS

Auf der diesjährigen Java One 2017 wurde bekannt gegeben, dass Funktionen aus dem geschlossenen Repository des Oracle JDK in das Open JDK integriert werden. Als Teil davon wurde AppCDS (Application Class Data Sharing) am 27.11. (28.11. In Japan) in OpenJDK eingegeben. 78b2ecdd3c4b). Heute möchte ich diese Funktion verschieben und ausprobieren. ~~ Wie auch immer, ich möchte, dass du auch nur einen der Abstürze machst. ~~

Das Oracle JDK stammt jedoch bereits aus JDK 8u40, sodass jeder, der es kennt, es bereits kennt.

Annahme

$ hg clone http://hg.openjdk.java.net/jdk/hs
$ cd hs
$ bash configure --with-extra-cflags="-Wno-error=deprecated-declarations -Wno-error=nonnull -Wno-error=maybe-uninitialized" --disable-warnings-as-errors
$ make images
$ ${PWD}/build/linux-x86_64-normal-server-release/images/jdk/bin/java -version
openjdk version "10-internal"
OpenJDK Runtime Environment (build 10-internal+0-adhoc.fedora.hs)
OpenJDK 64-Bit Server VM (build 10-internal+0-adhoc.fedora.hs, mixed mode)

Was ist CDS (Class Data Sharing)?

(System) Sie können eine Datei erstellen, die schreibgeschützte Metadaten einer Klasse namens "Shared Archives" enthält, die die aus der JAR-Datei verwendeten Klassen in die private interne JVM-Darstellung lädt und ausgibt. Es ist ein Mechanismus, bei dem die Startzeit verkürzt wird, da es schneller ist, diese Datei (freigegebenes Archiv) durch Speicherzuordnung wiederherzustellen, als die Klasse beim Starten der JVM von 1 zu laden.

Wie der Name schon sagt, kann dieses "gemeinsam genutzte Archiv" von mehreren JVMs gemeinsam genutzt werden. Wenn Sie es also für mehrere JVM-Prozesse freigeben, wird auch der Footprint (dynamischer Speicher-Footprint) unterdrückt. Freigegebene Archive werden standardmäßig installiert, je nachdem, wie die JRE installiert ist. Sie können es auch selbst machen.

CDS zielte auf System-JAR-Dateien ab, aber AppCDS zielte auch auf Benutzeranwendungscode ab. Richtig, CDS war nur die Zielklasse des Bootstrap-Klassenladeprogramms, aber AppCDS kann zusätzlich die Zielklassen des integrierten Systemklassenladeprogramms (auch als Anwendungsklassenladeprogramm bezeichnet), des Plattformklassenladeprogramms und des benutzerdefinierten Klassenladeprogramms archivieren.

Versuchen Sie es mit AppCDS

Ursprünglich ist es gut, den Effekt zu sehen, wenn die Klasse in einer großen Anzahl von Anwendungen ausgeführt wird. Da jedoch nichts einfach vorzubereiten ist, habe ich sie mit dem Standardwert Spring Initializr erstellt. Verbessern wir die Startzeit der Demo-App demo-0.0.1-SNAPSHOT.jar.

Die Standardeinstellung sieht folgendermaßen aus:

$ java -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.8.RELEASE)
:
2017-12-01 06:10:17.856  INFO 27529 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.103 seconds (JVM running for 1.841)
:

"1,103 Sekunden" ist die Basislinie.

Erstellen Sie eine Liste der zu archivierenden Klassen

Um ein freigegebenes Archiv zu erstellen, extrahieren Sie zuerst die Klassen, die von den folgenden Befehlen verwendet werden.

$ java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=demo.list -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher
:
2017-12-01 06:09:04.430  INFO 27451 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 320.159 seconds (JVM running for 454.536)
:

Rufen Sie die Liste "demo.list" der Nutzungsklassen ab, die beim Ausführen der Anwendung extrahiert wurden. Da es extrahiert wird, dauert es lange, bis es wie ein Idiot startet. Der Inhalt ist eine Liste von Klassen wie folgt.

$ cat demo.list
java/lang/Object
java/lang/String
:
org/springframework/boot/loader/JarLauncher
org/springframework/boot/loader/ExecutableArchiveLauncher
:

Natürlich ist es auch möglich, es von Hand hinzuzufügen.

Erstellen Sie ein freigegebenes Archiv

Nachdem wir eine Liste von Klassen haben, laden Sie sie einmal, sichern Sie sie und erstellen Sie ein freigegebenes Archiv.

$ /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=demo.list -XX:SharedArchiveFile=demo.jsa -XX:+IgnoreUnverifiableClassesDuringDump -cp target/demo-0.0.1-SNAPSHOT.jar
narrow_klass_base = 0x0000000800000000, narrow_klass_shift = 3
Allocated temporary class space: 1073741824 bytes at 0x00000008c0000000
Allocated shared space: 3221225472 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 1866
    instance classes   =  1789
    obj array classes  =    69
    type array classes =     8
Updating ConstMethods ... done.
Removing unshareable information ... done.
Scanning all metaspace objects ...
Allocating RW objects ...
Allocating RO objects ...
Relocating embedded pointers ...
Relocating external roots ...
Dumping symbol table ...
Dumping String objects to closed archive heap region ...
Dumping objects to open archive heap region ...
Relocating SystemDictionary::_well_known_klasses[] ...
Removing java_mirror ... done.
mc  space:      8800 [  0.0% of total] out of     12288 bytes [ 71.6% used] at 0x0000000800000000
rw  space:   5381944 [ 22.2% of total] out of   5382144 bytes [100.0% used] at 0x0000000800003000
ro  space:   9586008 [ 39.5% of total] out of   9588736 bytes [100.0% used] at 0x0000000800525000
md  space:      6160 [  0.0% of total] out of      8192 bytes [ 75.2% used] at 0x0000000800e4a000
od  space:   8581008 [ 35.3% of total] out of   8581120 bytes [100.0% used] at 0x0000000800e4c000
st0 space:    634880 [  2.6% of total] out of    634880 bytes [100.0% used] at 0x00000007bff00000
oa0 space:     81920 [  0.3% of total] out of     81920 bytes [100.0% used] at 0x00000007bfe00000
total    :  24280720 [100.0% of total] out of  24289280 bytes [100.0% used]

Holen Sie sich das freigegebene Archiv demo.jsa.

Überprüfen Sie, ob es schneller ist

Lassen Sie uns überprüfen, ob es schneller wurde, indem Sie das von uns erstellte freigegebene Archiv laden.

$ /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=demo.jsa -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher
:
2017-12-01 06:20:39.487  INFO 28908 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.992 seconds (JVM running for 1.414)
:

Es sind "0,992 Sekunden", was ungefähr 10% schneller ist, was ein gutes Gefühl ist. In Bezug auf absolute Zahlen ist AppCDS effektiver, da es aufgrund seiner Eigenschaften mehr Klassen gibt, sodass es in Anwendungen mit vielen Abhängigkeiten möglicherweise effektiver ist.

Sehen Sie, was wirklich los ist

Sie können überprüfen, ob das Laden der Klasse aus dem gemeinsam genutzten Archiv oder der Bibliothek (Klassendatei) erfolgt. Das Laden von Klassen kann mit -Xlog: class + load = info protokolliert werden.

AppCDS aktiviert

Sie können sehen, dass sowohl die Kernbibliothek als auch die Hauptklasse aus der Datei "Shared Objects" geladen werden.

$ /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xlog:class+load=info -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=demo.jsa -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher
[0.003s][info][class,load] opened: /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/lib/modules
[0.055s][info][class,load] java.lang.Object source: shared objects file
[0.055s][info][class,load] java.io.Serializable source: shared objects file
[0.055s][info][class,load] java.lang.Comparable source: shared objects file
:
[0.098s][info][class,load] org.springframework.boot.loader.Launcher source: shared objects file
[0.098s][info][class,load] org.springframework.boot.loader.ExecutableArchiveLauncher source: shared objects file
[0.098s][info][class,load] org.springframework.boot.loader.JarLauncher source: shared objects file
:

AppCDS deaktiviert

Sie können sehen, dass es aus der Bibliotheksdatei liest, anders als wenn es aktiviert ist.

$ /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xlog:class+load=info -Xshare:off -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher
[0.003s][info][class,load] opened: /home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/lib/modules
[0.013s][info][class,load] java.lang.Object source: jrt:/java.base
[0.014s][info][class,load] java.io.Serializable source: jrt:/java.base
[0.014s][info][class,load] java.lang.Comparable source: jrt:/java.base
:
[0.131s][info][class,load] org.springframework.boot.loader.Launcher source: file:/home/fedora/workspace/startup/demo/target/demo-0.0.1-SNAPSHOT.jar
[0.131s][info][class,load] org.springframework.boot.loader.ExecutableArchiveLauncher source: file:/home/fedora/workspace/startup/demo/target/demo-0.0.1-SNAPSHOT.jar
[0.131s][info][class,load] org.springframework.boot.loader.JarLauncher source: file:/home/fedora/workspace/startup/demo/target/demo-0.0.1-SNAPSHOT.jar
:

Zusammenfassung

Es gibt noch andere kleine Optionen, aber auf den ersten Blick scheinen die im Oracle JDK verfügbaren Funktionen wie angekündigt zu kommen. Eine einfache Demo-App, die das Framework verwendet, reduzierte den Betrag um etwa 10%. Eine App mit einer größeren Anzahl von Klassen kann jedoch effektiver sein. Wie wäre es mit der Verwendung während der Entwicklung?

Ich frage mich, ob es abstürzen wird, wenn es seltsamerweise mit AOT kombiniert wird.

[Extra Edition] Mach es schneller

/home/fedora/workspace/hs/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xlog:all=off -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:+UseSerialGC -Xverify:none -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=demo.jsa -cp target/demo-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher
2017-12-01 07:14:41.301  INFO 29775 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.811 seconds (JVM running for 1.178)

Es war "0,811 Sekunden"! Ich wollte auch eine winzige benutzerdefinierte Laufzeit ausprobieren, die unnötige Plattformmodule mit jlink vollständig entfernte, aber ich hatte keine Zeit, das war's für heute!

Zusätzlich zu diesen Laufzeitideen gibt es auch eine Möglichkeit, die JVM am Laufen zu halten, um die Startzeit der JVM zu verkürzen. Es gibt verschiedene Ansätze, aber Beispiele für die Implementierung sind Nagelpistole und [Falchion](https: // github), die eine unterbrechungsfreie Bereitstellung mit "SO_REUSEPORT" implementieren. Es kann interessant sein, einen Blick auf .com / kawasima / falchion zu werfen.

Recommended Posts

AppCDS @ OpenJDK
Installieren Sie OpenJDK
So installieren Sie OpenJDK 11 Memo
OpenJDK 11 Flugschreiber