Vielen Dank …!
Ja – hallo & Herzlich Willkommen… ich bin … und ich bin ein großer Freund der soliden, qualitativ hochwertigen und lösungsorientierte Softwareentwicklung. Das spiegelt sich auch darin, dass ich lange Jahre in Rollen wir Technology Advisor, Manager R&I und anderen oft erster Ansprechpartner in allen meth. & tech. Fragestellung war und bin.
Mein Fokus liegt dabei im Bereich rund um Java & Web. Java 17 bringt wirklich viele spannende & solide Verbesserungen mit. Daher freue ich mich besonders über Java 17, da wir dank der LTS-Version die vielen spannenden Innovationen nun sicher bald besser in unser aller Projektpraxis nutzen können.
In der heutigen Sessions stehten dabei weniger die Sprachfeatures im Vordergrund, sonder der Blick geht ein bisschen Richtung unter dei Haube und Tools.
… ich denke die Vorfreude auf Java 17 lohnt sich, denn z.B. 3 Dinge die Java 17 unter der Haube mit sich bringt sind…
… durch niedriglatente GCs und schnellere JVM Start zur Class-Data Sharing
…mit tiefgreifenden Diagnostikmittel, allen voran dem JDK Flight Recorder und dem JDK Mission Control…
-
Garbage Collectoren
-
Class-Data Sharing
-
Java Flight Recorder
-
Foreign Function & Memory
-
Tooling
-
Details & Maintenance
-
Kommen wir zum ersten Theme: GCs
-
Wichtiger Teil von Schwuppdizität
-
Zentral: Viele Verbesserung +2 neue GC Implementierungen
-
… aber ein blick auf: Was ist passiert?
11 |
[vial] ZGC Experimental |
12 |
[vial] Shenandoah Experimental |
13 |
[compress alt] ZGC Uncommit Memory |
14 |
[windows] & [apple] ZGC Support |
15 |
[award] Shenandoah Production-ready |
16 |
[chart line] ZGC Improvements |
-
Moderne Architekturen: Multi-Core & TB RAM
-
kurze GC Pausen im ms-Bereich
→ erkauft Responsiveness gegen Durchsatz -
(fast) vollständig parallel & nebenläufig
Pausen unabhängig von Größe des Heaps -
Unterstützen Class Unloading & Uncommit Memory
-
Einfach & Konfigurationsarm
-
Multi-Core & TB RAM
-
Ziel ist immer niedrige Latenz
-
bei G1 & Co gerne mal 200~500ms; hier: 1-10ms;
-
Schnellere Reaktion geringere Gesamtdurchsatz & Damit längere Laufzeit
„A scalable low-latency garbage collector“
-
GC Pausen kleiner 10ms 1ms
-
Durchsatz max. -15% gegenüber G1
-
Heapgrößen 8MB – 16TB
-
Einfaches Tuning
Colored Pointers & Load Barriers
→ Object Relocation
-
Aus dem Hause Oracle; ehemals kommerziell
-
JDK seit 11; Production since JDK 15; dann auch mit Linux/Win/macOS
-
Ziele …
-
Pausen unabhängig von Heap und Live- & Root-Set
-
Eigenschaften: Parallel, Regionen-basiert, ohne Generation, Compacting und NUMA-aware
-
Konzept: Colored pointers plus Load barriers → Relocation
-
-
"Schwuppizität" zum Preis von CPU und Gesamtlaufzeit
„A low-pause-time garbage collector by concurrent evacuation work“
-
ZGC sehr ähnlich Brooks (Forward) Pointers
-
Bietet verschieden Modi & Heuristic-Profile: adaptive, static, compact, aggressive
-
Beil zahlreichen Weak References → ZGC
-
Red Hat Kind → andere Service Offerings
-
Backports für JDK 8 & 11; auch 32-bit
-
ggü. ZGC: abhängig von Root- & Live-Set
-XX:+UseShenandoahGC
-
Name nach US Nationalpark
-
von Red Hat → auch Backports & Architekturen (z.B. ARM32)
-
seit 2013 und seit v12 im JDK; seit JDK15 Production
-
Pausen steigen mit Root Set / Live Set
-
Arbeitsbereich ist links! Rechts = Überlast
-
S & Z : Vergleichbare, gegenüber G1 deutlich niederige Latenzen
-
Verhalten bei wachsender Last: Hier scheint ZGC irgendwann den Punkt zu erreichen wo es nicht mehr mithalten kann; bei Shenandoah früher Latenz
-
Man sieht klar: G1 ist Tradeoff zwischen Latenz & Durchsatz → auch bei höhere Durchsatz stabil
GC | Optimiert für… | Kommentar |
---|---|---|
G1 |
Balance |
Üblicher Default. Überwiegend Nebenläufig. Zielt auf Balance von Durchsatz & Latenz. Ausreißer-Pausen bis 250~800ms. Guter Durchsatz. Häppchenweise Pausen an Zeitbudget orientiert. |
Shenandoah |
Latenz |
Auch verfügbar für JDK8, JDK11 und 32-bit. |
ZGC |
Latenz |
besser für |
ParallelGC |
Durchsatz |
Parallel & mehrere Threads. Hoher Durchsatz. |
SerialGC |
Speicherbedarf |
Single-Threaded. Empfiehlt sich nur für Heaps ~100MB. |
Zing/Azul |
Pauseless |
Nicht im OpenJDK; nur kommerziell verfügbar |
-
Epsilon Bug TLABs extension 14
-
Epsilon warns about Xms/Xmx/… 14
-
OldGen on NV-DIMM 12
-
Uncommit Memory 12
-
Improved Sparse PRT Ergonomics 13
-
NUMA-Aware Memory Alloc. JEP 354 14
-
Improved Heap Region Ergonomics 15
-
Concurrently Uncommit Memory 16
-
Disable large pages on Windows 15
-
Disable NUMA Interleaving on Win.15
[exclamation triangle] Many, many, more…
-
Old Gen auf alternativen Memory Geräten
-
G1 kann wieder Speicher freigeben
-
Auch ParallelGC erfährt Verbesserungen
-
CMS wurde entfernt
-
→ Viel mehr; teils nicht in den Release Notes
[level up alt] Upgrade lohnt sich!
[graduation cap] Probieren geht über Studieren!
[trash alt] Mut zum (probeweisen) Wegwerfen:
Alte Tuning-Parameter
[stopwatch] Latenz wichtig? → ZGC oder Shenandoah
- Class Data-Sharing
-
Reduziert Startzeiten & Speicherbedarf neuer JVMs durch
.jsa
Archiv mit Metadaten der Klassen.→ Klassen liegen vorgeparsed direkt für die JVM verwendbar vor. Das Archiv kann read-only eingebunden werden, was dem OS Caching & Sharing erlaubt.
Achtung: Archive sind JVM Plattform- und Versionspezifisch!
- Application Class-Data Sharing (AppCDS)
-
Erlaubt zusätzlich Applikations-Klassen in das CDS aufzunehmen.
- Default CDS Archive 12 JEP 341
-
JVM liefert nun per Default ein
classes.jsa
CDS-Archiv mit aus, welches ein Subset der häufigsten JDK-Klassen umfasst.
- Dynamic CDS Archive 13 JEP 350
-
Vereinfacht erheblich die Erstellung eigener AppCDS Archive durch automatische Auswahl und Archiverzeugung beim beenden der Java-Applikation.
$ java -Xshare:off -XX:DumpLoadedClassList=myclasses.txt -cp myapp.jar MyApp
$ java -Xshare:dump -XX:SharedArchiveFile=myapp.jsa \
-XX:SharedClassListFile=myclasses.txt -cp myapp.jar
$ java -XX:ArchiveClassesAtExit=myapp.jsa -cp myapp.jar MyApp
$ java -XX:SharedArchiveFile=myapp.jsa -cp myapp.jar MyApp
-
Bedenken: Nur die Klassen die die JVM während des Lauf lädt.
-
→ Gunnar Morling
-
Teils bis zu 40% Reduktion in Startup-Times
jlink
-
Noch mehr Potential mit Kombination von
jlink
-
Wir erinnern uns:
jlink
Erlaubt die Auswahl einer Teilmenge von Modules für ein custom runtime images -
Nur benötigte Module → weniger Klassen/Balast
-
-
Ergebnis
-
Kleinere Images
-
Mit AppCD deutlich schneller: 1,8s → 0,8s
-
-
Nachteil: Komplexität des Gesamtbuilds
Kommen wir zu "mehr Druchblick" mit JavaFR & JMC
JDK Flight Recorder (JFR) JEP 328
-
OS, JVM, JDK & App Diagnostik
-
extrem geringer Overhead (~1%)
-
built-in & jederzeit aktivierbar
-
always-on möglich → Timemachine
→ [cogs] Production Profiling & Monitoring
-
Ehemals kommerzielles JVM Addon "Java Flight Recorder"
-
seit Java 11 OpenJDK Bestandteil
-
Aktivierbar für neue und bereits laufende Java-Instanzen
-
Zielmetrik: Weniger als 1% Overhead → no measurable impact on the running application → klare Ausrichtung für Produktionsverwendung
-
Built by the JVM/JDK people
-
→ access to data already collected, more accurate, faster
-
Safe and reliable in production
-
-
always on → Time machine – just dump the recording data when a problem occurs, and see what the runtime was up to before, up to, and right after the problem occurred.
-
Even on JVM crash → JFR data avail in dump
JDK Mission Control also contains other tools, such as a JMX Console, and HPROF-dump analyzer and more.
Flight Recorder Demo
jcmd
jcmd <pid> JFR.start jcmd <pid> JFR.dump \ filename=record.jfr
Optionen: filename
, delay
, dumponexit
, duration
, maxage
, maxsize
, …
jfr print record.jfr jfr print \ --events CPULoad \ --json record.jfr jfr summary record.jfr
-
PID identifizieren
-
JFR starten (& konfigurieren)
-
Optionen → bei Crash, delay, laufzeit, Ringbuffer-Parameter
-
Events sichten
-
Filter nach Event & Kategorie
-
→ Export JSON mgl
-
Grobe Summe
-
Grobe Orientierung ohne ext. mittel; für mehr Einsichten brauchts aber Tools.
-
Ex-Payware "Java F…"; seit v11 Open "JDK F…"
-
8.1+ für JFR Events von JDK17 (Heap)
-
JMX Live Status / Properties
-
Hilfreich: Automatisierte Alert bei Grenzwerte
-
Aber auch: JFR dumps laden bzw. live tracen
-
Erlaubt grobe Kategorieeinstellung
-
… und per einzelnem JFR Event
JFR Event Streaming JEP 349 14 16
-
Vor JDK14: Start JFR → Dump (File/JMX) → Analyze.
-
Gut für Profiling, schlecht für Continuous Monitoring
-
Mit Java 14: JFR Event Streaming:
-
API anbieten um (kontinuierlich) Events des JFR Disk Repo lesen zu können
-
Ziel: Trivial kontinuierlich JFR Events monitoren und darauf reagieren können
-
Neu in JDK 16:
-
Erlaubt auch Remote Streaming
-
Neues, leichtgewichtiges
jdk.ObjectAllocationSample
default on
-
-
GraalVM ab 21.2 unterstützt ebenfalls JFR
Reported sekündlich CPU Usage und aktive Locks länger als 10ms:
try (var rs = new RecordingStream()) {
rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
rs.enable("jdk.JavaMonitorEnter").withThreshold(Duration.ofMillis(10));
rs.onEvent("jdk.CPULoad", event -> {
System.out.println(event.getFloat("machineTotal"));
});
rs.onEvent("jdk.JavaMonitorEnter", event -> {
System.out.println(event.getClass("monitorClass"));
});
rs.start(); // Blockierender Aufruf, bis Stream endet/geschlossen wird
// rs.startAsync(); Alternative im separaten Thread
}
JFR Eventtypen: https://bestsolution-at.github.io/jfr-doc/
EventStream.openRepository()) {…}
EventStream.openRepository(Path.of("…")))
try (var stream = new RecordingStream()) { … }
String url = "service:jmx:rmi:///jndi/rmi://myhost.de:7091/jmxrmi";
JMXConnector c = JMXConnectorFactory.connect(new JMXServiceURL(url));
MBeanServerConnection conn = c.getMBeanServerConnection();
try (RemoteRecordingStream stream = new RemoteRecordingStream(conn)) { … }
import jdk.jfr.*;
@Name("de.bentolor.ButtonPressed")
@Label("Button Pressed")
@StackTrace(false)
public class ButtonEvent extends Event {
@Label("Button name")
public String name;
@Label("Source")
public String trigger;
@Label("Number of Bounces")
@DataAmount
public int bounces;
@Label("Has timeouted")
public boolean timeouted;
}
ButtonEvent evt = new ButtonEvent();
if(evt.isEnabled()) {
evt.name = "Button 1";
evt.trigger = "Keyboard";
evt.begin();
}
// doSomething()
if(evt.isEnabled()) {
evt.end();
evt.timeouted = false;
evt.bounces = 3;
evt.commit();
}
- Timeshift-Analyse
-
Recording mitlaufen lassen und bei Performance-Problemen rückwirkend seit Problemstartpunkt aus dem JFR Event Repository extrahieren & analysieren („Timeshift“)
Exkurs: Preview features Preview JEP 12
Auslieferung experimenteller Sprach- und JVM-Features,
oft in Iterationen, zur Förderung von frühem Community Feedback.
z.B.: Pattern Matching, Switch Expression, Text Blocks, Records, Sealed Classes
javac --enable-preview …
java --enable-preview …
Keine Cross-compilation mittels --release xx
möglich!
-
Forces awareness by using toggle switch on compiling and running
-
Typisch mehrere Iterationen (z.B.
switch
-Statement) -
Stabilisierung auf LTS; in 17 LTS daher kein Preview Feature
Exkurs: Incubator Modules Incubator JEP 11
Analog Preview Features für nicht-finale APIs und Tools
javac --add-modules jdk.incubator.foo …
java --add-modules jdk.incubator.foo …
z.B.: HTTP/2 Client, Packaging Tool, …
Interessanterweise 2 "Incubator" in der LTS Version: "Vector API" und "Foreign Function & Memory API"
-
26 Jahre alt
-
erfordert
.c
&.h
-Files -
mehrstufiger Prozess:
kleinteilig & brüchig
↓
sehr verworren
Motivation Project Panama Incubator JEP 412
Starke Drittbibliotheken (z.B. ML/AI) mit dynamischer Entwicklung
Tensorflow, OpenSSL, libsodium, …
Introduce an API by which Java programs can interoperate with code and data outside of the Java runtime […] without the brittleness and danger of JNI.
Ziele: Einfachheit – Performance – Sicherheit
-
Motivation: ML → Python Ecosystem → vs. re-implementing
-
Einfachheit → nur Java
-
→ hofft auf Tooling
-
Performance: Vergleichbar mit JNI
-
Umschiffen alter Scrhanken wie max 2GB mit ByteBuffer max. 2GB und foreign Memory GC-manages.
-
Sicherheit: Abkommen von
sun.misc.Unsafe
;
-
Zwei JEPs / APIs: Memory Access API & Foreign Linker API
-
erstmals JDK14, dann 15, 16 und nun zusammengeführt in 17
import java.lang.invoke.*;
import jdk.incubator.foreign.*;
class CallPid {
public static void main(String... p) throws Throwable {
var libSymbol = CLinker.systemLookup().lookup("getpid").get(); (1)
var javaSig = MethodType.methodType(long.class); (2)
var nativeSig = FunctionDescriptor.of(CLinker.C_LONG); (3)
CLinker cABI = CLinker.getInstance();
var getpid = cABI.downcallHandle(libSymbol, javaSig, nativeSig); (4)
System.out.println((long) getpid.invokeExact()); (5)
}
}
-
adressiertes Symbol – hier via Lookup in den System Libraries
-
gewünschte Java-Signatur des Java Foreign Handles
-
Ziel-Signatur der aufzurufenden C-Funktion
-
Funktionshandle beziehen
int crypto_box_seal(unsigned char *c, const unsigned char *m,
unsigned long long mlen, const unsigned char *pk)
…liest Text aus *m
, Zielschlüssel *pk
und schreibt
verschlüsseltes Ergebnis in nativen Speicher *c
↓
var cryptoBoxSeal = CLinker.getInstance().downcallHandle(
SymbolLookup.loaderLookup().lookup("crypto_box_seal").get(),
MethodType.methodType(int.class,
MemoryAddress.class, MemoryAddress.class,
long.class, MemoryAddress.class),
FunctionDescriptor.of(C_INT,
C_POINTER, C_POINTER,
C_LONG_LONG, C_POINTER) );
-
libsodium Funktion
-
erwartet drei Pointer
-
java:
MemoryAddress
-
C:
C_POINTER
-
ResourceScope
verwaltettry (var scope = ResourceScope.newConfinedScope()) { … }
var plainMsg = CLinker.toCString("abc", scope);
var cipherText = scope.allocate(48 + plainMsg.byteSize(), scope);
var pubKey = scope.allocateArray(C_CHAR, publicKey);
var ret = (int) cryptoBoxSeal.invokeExact( cipherText.address(), plainMsg.address(),
(long) plainMsg.byteSize(), pubKey.address());
return cipherText.toByteArray();
die Frage: Wie mit Java nativen Speicher bekommen?
-
Foreign Memory → managed by GC
-
dazu an separates
ResourceScope
-Objekt gebunden
Generiert aus direkt aus .h
-Dateien passende API Wrapper
als .class
oder .java
mit den notwendigen Foreign API-Aufrufen.
Nicht direkt in JDK 17 enthalten, sondern via Panama EAP JDK Builds (siehe Link).
$ jextract -t de.bentolor /usr/include/unistd.h
import de.bentolor.unistd_h;
class CallPid {
public static void main(String[] args) {
System.out.println( unistd_h.getpid() );
}
}
-
Nicht Teil des JDK, separater Download
-
Erzeugt / Generiert den Boiler Code
-
Da große 89MB LLVM Dependency, vermutlich nie JDK Bestandteil
mkdir hello-python
cd hello-python
locate Python.h
jextract -t de.bentolor \
-l python3.8 \
-I /usr/include/python3.8/ \
-I /usr/include/ \
/usr/include/python3.8/Python.h
joe Schlange.java
java --add-modules jdk.incubator.foreign \
--enable-native-access=ALL-UNNAMED \
-Djava.library.path=/usr/lib/x86_64-linux-gnu/ \
Schlange.java
jextract -t de.bentolor \
-l python3.8 \
-I /usr/include/python3.8/ \
-I /usr/include/ \
--source
/usr/include/python3.8/Python.h
bat de/bentolor/Python_h.java
bat de/bentolor/Python_h_4.java
/s int PyRun_S
import jdk.incubator.foreign.*;
import de.bentolor.Python_h;
public class Schlange {
public static void main(String[] args) {
String script = """
print(sum([33, 55, 66]));
print('Hello Python 3!')
""";
Python_h.Py_Initialize();
try (var scope = ResourceScope.newConfinedScope()) {
var str = CLinker.toCString(script, scope);
Python_h.PyRun_SimpleStringFlags(
str, MemoryAddress.NULL);
Python_h.Py_Finalize();
}
}
}
Werkzeug zum Erstellen & Paketieren eigenständiger Java-Applikationen
[windows] → .msi
und .exe
[apple] → .pkg
und .dmg
[linux] → .deb
und .rpm
Start-Optionen (JVM/App)
Meta-Daten
Datei-Assoziationen
Splash-Screen
Auto-Update Mechanismus
-
Preview mit JDK14, stabilisiert mit JDK16
-
Native Installerformate für natürliche Installations UX
Das Javadoc-Tool hat mit JDK16 umfassende Verbesserungen erfahren…
-
Verbesserte Suche
-
Fehler zeigen Code-Ausschnitt
-
Neues/Verbessertes New, Deprecated, Related Package
-
Mobile-friendly Layout
-
autom. Links zur JDK API
-
Checks für leere Absätze
-
Bessere "Typ"-Terminologie
-
Bessere Darstellung von
@see
, Paketen, Nested Class, u.a.
Hilfreiche Nullpointers JEP 358 14
class MyClass {
record Person(String name, String email) {}
public static void main(String[] args) {
var p = new Person("Peter", null); (1)
var e = p.email().toLowerCase();
}
}
$ java MyClass.java
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toLowerCase() because the return value of "MyClass$Person.email()" is null
at MyClass.main(MyClass.java:5)
-
Für Namen von lokalen Variablen und Lambdas mit
-g:vars
compilieren!
-
Erforderte früher
-XX:+ShowCodeDetailsInExceptionMessages
, nun default!
-
Strongly Encapsulate JDK Internals JEP 391
-
macOS/AArch64 Port JEP 391
-
SecurityManager
forRemoval
JEP 411 -
Always-Strict Floating-Point Semantics JEP 306
-
Asynchrones Unified JVM Logging (
-Xlog:async
) -
Ausführlichere Crashs:
-XX:+ExtensiveErrorReports
-
Unicode 10 → 13; CLDR 33 → 39
-
Krypto: Deprecated Ciphers/Signatures, Enhanced PRNG JEP 356
-
Mit JDK17
--illegal-access
nicht mehr möglich-
Motivation: Jigsaw
-
Aber: sun.misc.Unsafe will remain available.
-
Ziel: Druck weiter erhöhen
-
-
-XX:+ExtensiveErrorReports
→ ausführlichere Crash-hs_err….log
-
StrictFPS: Revert JDK 1.2 Change für x87 Coprozessoren
-
Porting the JDK to MacOS/AArch64 → Apple M1.
-
PRNG: Neue Impl. supporten
-
Polyglot VM
-
In Java geschrieben VM die auf div. Sprachen zielt
-
gemeinnsame Runtime → multiple language with zero overhead
-
Kann mit LLVM native images produzieren
-
Ahead-of Time compiler (AoT)
-
Polyglotte VM für div. Sprachen
→ JVM (Java, Kotlin, Scala, …)
→ LLVM (C, C++) → native
→ Java Script, Python, Ruby, R
-
Sprachen sharen Runtime
→ Zero Interop Overhead -
Native executables (SubstrateVM)
→ Kleiner Startup & Memory -
GraalVM Community & Enterprise
Helidon, Quarkus.io, Micronaut, Spring Fu, Ktor, …
→ zielen auf GraalVM AoT & Microservices, z.B. via IoC zur Compiletime
-
Fokus: AoT
-
Mehrteilig:
-
Graal VM & Substrate VM as runtime
-
-
Benefits
-
AoT → schnellere Startzeiten vs. JIT
-
Native Images → kleinere Startup/Memory → Container
-
Limitations: Dynamic (Reflection)
-
Beeindruckend: GraalVM ab 21.2 unterstützt ebenfalls JFR
-
-
Commercial offerings "GraalVM Enterprise"
-
zahlreiche Frameworks zielen auf GraalVM AoT & Microservices
-
z.B. IoC zur Compiletime via APT vs. Laufzeit
-
[twitter] @bentolor
[at] ben@tolor.de
[github] bentolor/java17-lts-presentation
Proudly made with:
asciidoctor-revealjs
, pexels.com Videos & freeimages.com images