GraalVM – Die Zukunft der JVM?

14.12.2020

Oracle baut mit dem Projekt GraalVM eine (mögliche) Plattform für die Zukunft von Java. Auf der Website werden “High Performance”, “Ahead-of-Time Compilation”, “Language Choice”, und “Advanced Tools” als prominente Vorteile beworben.

Mit diesem Post möchte ich meine ersten Erfahrungen und Einschätzungen über die GraalVM teilen.

Installation

Die Installation von GraalVM ist erst einmal so einfach wie auch die Installation eines klassischen JDKs. Letztendlich bringt die GraalVM ein JDK mit und kann somit direkt als Ersatz für ein klassisches JDK verwendet werden. Wenn man aber von den Vorteilen der GraalVM profitieren möchte, sind weitere Installationsschritte notwendig. Dazu gibt es das Kommandozeilen Programm gu (GraalVM Updater). Damit kann man über einfache Befehle verfügbare Erweiterungen abfragen und eben auch installieren. Möchte man z.B. Anwendungen in eine native ausführbare Datei kompilieren, so muss man neben der Erweiterung “native-image” auch noch manuell Plattformspezifische Werkzeuge installieren. Die Dokumentation sagt dazu folgendes:

For compilation native-image depends on the local toolchain. Install glibc-devel, zlib-devel (header files for the C library and zlib) and gcc, using a package manager available on your OS. Some Linux distributions may additionally require libstdc+±static.

Bei meinem Versuchen ist auch aufgefallen, dass es manche Funktionen noch nicht in allen GraalVM Versionen gibt und dass sich die GraalVM Versionen durch die unterstütze Java Version (Java 8 und Java 11) und die vorhandenen Erweiterungen unterscheiden. Man muss also eventuell aufpassen, welche Version man installiert. Das sind aber Probleme, die sich mit zukünftigen Versionen sicher noch bessern werden.

Genauso erfolgt über gu die Installation der Unterstützung weiterer Programmiersprachen. Wenn man zum Beispiel die Javascript Unterstützung “js” installiert, so landen die entsprechenden Werkzeuge im bin Ordner der GraalVM Installation. In diesem Fall sind das dann zum Beispiel node, npm und npx, die für die Verwendung mit GraalVM angepasst wurden. Man muss hier nur aufpassen, dass man diese nicht mit bereits installierten Versionen der “echten” Programme durcheinander bringt (Stichwort PATH).

Die zusätzlichen Funktionen, die GraalVM gegenüber einem klassischen JDK mitbringt, machen sich also auch in der Installation bemerkbar. Gerade die “native-image” Funktion kann dazu führen, dass man plattformabhängige Werkzeuge installieren muss. Gerade das ist eine Tür, die man als Java Entwickler eventuell nicht unbedingt aufstoßen möchte.

“High Performance” und “Ahead-of-Time Compilation”

Die GraalVM verspricht eine sehr performante Ausführung von Anwendungen. Neben Optimierungen in der Implementierung soll diese dadurch werden, dass man aus dem Quellcode eine native und voroptimierte Anwendung erstellt. Das bedeutet, dass man am Ende nicht wie man es von Java her kennt, ein Artifakt in der Form von Bytecode heraus bekommt, welches dann in der JVM ausgeführt wird, sondern eher wie man es von C/C++ usw. kennt, ein natives Executable (unter Windows dann eine *.exe Datei). Das hat den Vorteil, dass das Programm dann noch näher an der Hardware läuft, die Zwischenschicht der JVM wegfällt und damit Dinge wie das starten der Virtuellen Maschine, das Interpretieren des Bytecodes und die Optimierungen zur Laufzeit (Stichwort JIT) wegfallen. “Laufzeit” ist hierbei ein Zauberwort.

Nicht nur die GraalVM als Plattform optimiert für die Laufzeit, sondern auch die Frameworks, die um GraalVM herum entstanden sind. Die bekanntesten sind wohl Quarkus, Helidon und Micronaut. Dieser Trend blieb natürlich auch bei dem wohl bekanntesten Java Framework Spring nicht unbemerkt und somit gibt es große Bemühungen, eine an die GraalVM Plattform angepasste Version von Spring herauszubringen. Spring ist hier ein gutes Beispiel, wenn man besser verstehen möchte, wie GraalVM tickt. Ein intensiv von Spring genutzes Java Feature sind Annotationen. Fast alles lässt sich über Annotationen konfigurieren und steuern. Annotationen und die damit verbundene Reflection sind Funktionen, die normalerweise zur Laufzeit über die JVM zur Verfügung gestellt werden. Wenn man sich aber wie GraalVM die VM zur Laufzeit spart, dann muss man die notwendigen Informationen bereits beim Bauen in das resultierende Artifakt integrieren. Eine Funktion die GraalVM mitbringt um diese Anforderung zu realisieren heißt AutomaticFeature. Es handelt dabei um einen Mechanismus zur Metaprogrammierung ähnlich wie z.B. Java Agenten oder Makros aus diversen Programmiersprachen. Beim bauen werden die „AtomicFeature“s ausgeführt und diese definieren dann Informationen über die Anwendung, die zur Laufzeit verwendet werden können. An dieser Stelle merkt man vielleicht den Zwiespalt von GraalVM. Man bekommt die Vorteile nicht einfach geschenkt, sondern muss umdenken und auf vielleicht liebgewonnene Funktionen wie Laufzeit Reflection verzichten, sowie längere Zeiten beim bauen hinnehmen. Dafür bekommt man eine schnellere Anwendung, die auch sehr schnell startet. Letztendlich würden viele dieser Optimierungen auch bei einer klassischen JVM funktionieren. Wichtig hierbei ist, dass man die GraalVM ja auch wie die klassische JVM mit der VM zwischen der Anwendung und der Hardware betreiben kann. Dann bekommt man ohne großen Umstellungsaufwand eventuell etwas mehr Performanz, was aber aus meiner Sicht kein “Verkaufsargument” für die GraalVM ist. Fazit: Der Performanzaspekt geht bei GraalVM auch mit einer anderen Philosophie einher, was “Laufzeit” und “Bauzeit” betrifft, der man sich bewusst sein sollte.

“Language Choice”

Für mich ist die Funktion, auch andere Sprachen abseits von Java auf der GraalVM ausführen zu können, eine Funktion, auf die ich besonders gespannt war, da ich sehr gerne die Abwechslung von verschiedenen Programmiersprachen genieße und auch in einem Projekt den Anwendungsfall hatte, dass Anwendungen, die in verschiedenen Sprachen (Python, C) geschrieben wurden, in eine Java Anwendung integriert werden mussten.
Mit der GraalVM scheint Oracle zu versuchen, auch Entwickler abseits der Javawelt anzusprechen. Im Prinzip sollen alle bekannten und auch unbekannten Sprachen früher oder später unterstützt werden. Um das zu erreichen, wurden Schichten hinzugefügt, um beliebige Programmiersprachen möglichst einfach auf die GraalVM Plattform zu portieren und sie damit auf der GraalVM ausführbar zu machen. Sprachen, die bisher schon auf der JVM liefen, werden auch weiterhin out-of-the-box von der GraalVM unterstützt. Andere Sprachen können über das Truffle Framework in die GraalVM integriert werden. Dabei handelt es sich um einen Werkzeugkasten, der es ermöglicht, einen Interpreter für eine Programmiersprache zu implementieren. Auf dieser Basis gibt es schon diverse Sprachen, die unterstützt werden, wie z.B. Ruby, Python oder Javascript. Da es auch einen Truffle Interpreter für das LLVM Format gibt, werden automatisch auch alle Sprachen unterstützt, die sich in das LLVM Format kompilieren lassen (wie z.B. c, c++ oder Rust). Jede Sprache bringt seine eigenen Vor- und Nachteile mit. Wechselt man mit einer Sprache auf die GraalVM, dann ist es wahrscheinlich, dass man eventuell manche Vorteile gegen Nachteile tauscht und umgekehrt. Auch wenn verschiedene Komponenten in verschiedenen Sprachen vorliegen, sollte man ja grundsätzlich darauf achten, dass die Schnittstellen untereinander möglichst gering sind. Für solche geringen Koppelungen reichen oft die bekannten Möglichkeiten wie JNI, Scriptengines, Sockets, das Fielsystem oder Prozesse aus. GraalVM bringt das ganze aber auf ein neues Level. Der Dreh- und Angelpunkt ist die Frage, wer sich wem annähren möchte. Soll die Javawelt sich mehr in die Richtung der Ökosysteme andere Sprachen öffnen oder sollen wir mit anderen Sprachen gegen das Javaökosystem entwickeln (hier ein Beispiel)? Ich kann mir beides nicht so richtig vorstellen, da es immer einen Verlierer geben würde und sich Programmiercommunities nicht so einfach auf eine neue Plattform ziehen lassen. Meist sind auch die Libraries, die für eine spezifische Sprache geschrieben sind, die bessere Wahl (sofern es überhaupt welche gibt), da diese auf die Eigenheiten einer Sprache optimiert sind. Vielleicht aber bringt ja die Zukunft hier ein noch besseres Tooling mit sich, welches uns alle langsam auf die GraalVM zieht. Interessant fand ich zum Beispiel die Anstrengungen, den poligloten Ansatz der GraalVM für z.B. Language Server (LSP) zu nutzen. Genau auf solche Innovationen, die man vielleicht bisher auch noch gar nicht kommen gesehen hat, bin ich besonders gespannt.

Fazit

Die Funktionen der GraalVM sind teilweise wirklich innovativ und erfordern deshalb auch ein Umdenken, das bei vielen Entwicklern nicht von Heute auf Morgen passieren wird. Die Vorteile kommen aus meiner sicht noch nicht perfekt zur Geltung, eben weil sie oft nicht umsonst sind oder noch an Kinderkrankheiten leiden. Welche Funktionen der GraalVM sich am Ende durchsetzen können, ist aus meiner Sicht ungewiss. Ich sehe aber ein großes Potential und kann Oracle für die mutigen Schritte loben.

Mehr zu Java Programmierung erfahren

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*