Java Valhalla Projekt

1. Übersicht

In diesem Artikel werden wir uns mit dem Projekt Valhalla befassen - den historischen Gründen dafür, dem aktuellen Entwicklungsstand und dem, was es für den täglichen Java-Entwickler nach seiner Veröffentlichung auf den Tisch bringt.

2. Motivation und Gründe für das Valhalla-Projekt

In einem seiner Vorträge sagte Brian Goetz, Java-Spracharchitekt bei Oracle, eine der Hauptmotive für das Valhalla-Projekt sei der Wunsch , die Java-Sprache und die Laufzeit an moderne Hardware anzupassen . Bei der Konzeption der Java-Sprache (vor ungefähr 25 Jahren zum Zeitpunkt des Schreibens) waren die Kosten für einen Speicherabruf und eine Rechenoperation ungefähr gleich.

Heutzutage hat sich dies verschoben, wobei Speicherabrufoperationen 200- bis 1000-mal teurer sind als arithmetische Operationen. In Bezug auf das Sprachdesign bedeutet dies, dass Indirektionen, die zu Zeigerabrufen führen, sich nachteilig auf die Gesamtleistung auswirken.

Da die meisten Java-Datenstrukturen in einer Anwendung Objekte sind, können wir Java als zeigerlastige Sprache betrachten (obwohl wir sie normalerweise nicht direkt sehen oder bearbeiten). Diese zeigerbasierte Implementierung von Objekten wird verwendet, um die Objektidentität zu aktivieren, die selbst für Sprachmerkmale wie Polymorphismus, Veränderlichkeit und Sperren genutzt wird. Diese Funktionen sind standardmäßig für jedes Objekt verfügbar, unabhängig davon, ob sie wirklich benötigt werden oder nicht.

Nach der Identitätskette, die zu Zeigern führt, und Zeigern, die zu Indirektionen führen, wobei Indirektionen Leistungsnachteile aufweisen, besteht eine logische Schlussfolgerung darin, diejenigen für Datenstrukturen zu entfernen, die diese nicht benötigen. Hier kommen Werttypen ins Spiel.

3. Werttypen

Die Idee von Werttypen besteht darin , reine Datenaggregate darzustellen . Dies kommt mit dem Löschen der Funktionen von regulären Objekten. Wir haben also reine Daten ohne Identität. Dies bedeutet natürlich, dass wir auch Funktionen verlieren, die wir mithilfe der Objektidentität implementieren könnten. Folglich kann ein Gleichheitsvergleich nur auf der Grundlage des Zustands erfolgen. Daher können wir keinen gegenständlichen Polymorphismus verwenden und wir können keine unveränderlichen oder nicht nullbaren Objekte verwenden.

Da wir keine Objektidentität mehr haben, können wir auf Zeiger verzichten und das allgemeine Speicherlayout von Werttypen im Vergleich zu einem Objekt ändern. Schauen wir uns einen Vergleich des Speicherlayouts zwischen der Klasse Point und dem entsprechenden Werttyp Point an.

Der Code und das entsprechende Speicherlayout einer regulären Point- Klasse wären:

final class Point { final int x; final int y; }

Andererseits wäre der Code und das entsprechende Speicherlayout eines Werttyps Punkt :

value class Point { int x; int y }

Auf diese Weise kann die JVM Werttypen in Arrays und Objekte sowie in andere Werttypen reduzieren. Im folgenden Diagramm zeigen wir den negativen Effekt von Indirektionen, wenn wir die Point- Klasse in einem Array verwenden:

Andererseits sehen wir hier die entsprechende Speicherstruktur eines Werttyps Point [] :

Außerdem kann die JVM Werttypen auf dem Stapel übergeben, anstatt sie auf dem Heap zuweisen zu müssen. Letztendlich bedeutet dies, dass wir Datenaggregate erhalten, deren Laufzeitverhalten ähnlich wie bei Java-Grundelementen wie int oder float ist .

Im Gegensatz zu Grundelementen können Werttypen Methoden und Felder haben. Wir können auch Schnittstellen implementieren und diese als generische Typen verwenden. Wir können die Werttypen also aus zwei verschiedenen Blickwinkeln betrachten:

  • Schnellere Objekte
  • Benutzerdefinierte Grundelemente

Als zusätzliches Sahnehäubchen können wir Werttypen als generische Typen ohne Boxen verwenden. Dies führt uns direkt zu der anderen großen Funktion von Project Valhalla: spezialisierten Generika.

4. Spezialisierte Generika

Wenn wir über Sprachprimitive generieren möchten, verwenden wir derzeit Boxed-Typen wie Integer für int oder Float für float . Dieses Boxen erzeugt eine zusätzliche Indirektionsebene, wodurch der Zweck der Verwendung von Grundelementen zur Leistungssteigerung in erster Linie zunichte gemacht wird.

Daher sehen wir viele spezielle Spezialisierungen für primitive Typen in vorhandenen Frameworks und Bibliotheken wie IntStream oder ToIntFunction . Dies geschieht, um die Leistungsverbesserung bei der Verwendung von Grundelementen aufrechtzuerhalten.

Spezialisierte Generika sind also ein Versuch, die Notwendigkeit für diese „Hacks“ zu beseitigen. Stattdessen versucht die Java-Sprache, generische Typen für praktisch alles zu aktivieren: Objektreferenzen, Grundelemente, Werttypen und möglicherweise sogar ungültig .

5. Schlussfolgerung

Wir haben einen Blick auf die Änderungen geworfen, die Project Valhalla an der Java-Sprache vornehmen wird. Zwei der Hauptziele sind eine verbesserte Leistung und weniger undichte Abstraktionen.

Die Leistungsverbesserungen werden behoben, indem Objektdiagramme abgeflacht und Indirektionen entfernt werden. Dies führt zu effizienteren Speicherlayouts und weniger Zuordnungen und Speicherbereinigungen.

Die bessere Abstraktion ergibt sich aus Grundelementen und Objekten, die sich bei Verwendung als generische Typen ähnlicher verhalten.

Ein früher Prototyp des Projekts Valhalla, der Werttypen in das bestehende Typensystem einführt, trägt den Codenamen LW1.

Weitere Informationen zum Projekt Valhalla finden Sie auf der entsprechenden Projektseite und in den JEPs:

  • Projekt Valhalla
  • JEP 169: Wertobjekte
  • JEP 218: Generika über primitive Typen