Java Valhalla Project

1. Overzicht

In dit artikel gaan we kijken naar Project Valhalla - de historische redenen ervoor, de huidige stand van ontwikkeling en wat het de dagelijkse Java-ontwikkelaar oplevert zodra het is uitgebracht.

2. Motivatie en redenen voor het Valhalla-project

In een van zijn toespraken zei Brian Goetz, Java-taalarchitect bij Oracle, dat een van de belangrijkste motivaties voor het Valhalla-project de wens is om pas de Java-taal en runtime aan moderne hardware aan. Toen de Java-taal werd bedacht (ongeveer 25 jaar geleden op het moment van schrijven), de kosten van het ophalen van het geheugen en een rekenkundige bewerking waren ongeveer hetzelfde.

Tegenwoordig is dit verschoven, waarbij geheugenophaalbewerkingen 200 tot 1000 keer duurder zijn dan rekenkundige bewerkingen. In termen van taalontwerp betekent dit dat indirecte acties die leiden tot het ophalen van aanwijzers een nadelig effect hebben op de algehele prestaties.

Aangezien de meeste Java-datastructuren in een applicatie objecten zijn, kunnen we Java beschouwen als een taal met veel aanwijzers (hoewel we ze meestal niet direct zien of manipuleren). Deze op pointer gebaseerde implementatie van objecten wordt gebruikt om objectidentiteit mogelijk te maken, die zelf wordt gebruikt voor taalkenmerken zoals polymorfisme, veranderlijkheid en vergrendeling. Deze functies zijn standaard voor elk object, ongeacht of ze echt nodig zijn of niet.

Het volgen van de identiteitsketen die leidt tot aanwijzingen en aanwijzingen die leiden tot indirecte, waarbij indirecte prestatienadelen hebben, is een logische conclusie om die te verwijderen voor datastructuren die ze niet nodig hebben. Dit is waar waardetypes in het spel komen.

3. Waardetypes

Het idee van waardetypes is om vertegenwoordigen pure data-aggregaten. Dit komt met het laten vallen van de kenmerken van gewone objecten. We hebben dus pure data, zonder identiteit. Dit betekent natuurlijk dat we ook functies verliezen die we zouden kunnen implementeren met behulp van objectidentiteit. Bijgevolg, gelijkheidsvergelijking kan alleen plaatsvinden op basis van de staat. We kunnen dus geen representatief polymorfisme gebruiken, en we kunnen geen onveranderlijke of niet-nulbare objecten gebruiken.

Omdat we geen objectidentiteit meer hebben, kunnen we pointers opgeven en de algemene geheugenlay-out van waardetypes veranderen in vergelijking met een object. Laten we eens kijken naar een vergelijking van de geheugenlay-out tussen de klassen Punt en het bijbehorende waardetype Punt.

De code en de bijbehorende geheugenlay-out van een gewone Punt klasse zou zijn:

laatste klasse Punt {final int x; laatste int y; }

Aan de andere kant zijn de code en de bijbehorende geheugenlay-out van een waardetype Punt zou zijn:

waardeklasse Punt {int x; int y}

Hierdoor kan de JVM waardetypen afvlakken in arrays en objecten, evenals in andere waardetypen. In het volgende diagram presenteren we het negatieve effect van indirecte effecten wanneer we de Punt klasse in een array:

Aan de andere kant zien we hier de corresponderende geheugenstructuur van een waardetype Punt[]:

Het stelt de JVM ook in staat om waardetypen door te geven aan de stapel in plaats van ze op de heap te moeten toewijzen. Uiteindelijk betekent dit dat we gegevensaggregaten krijgen die runtime-gedrag vertonen dat vergelijkbaar is met Java-primitieven, zoals int of vlotter.

Maar in tegenstelling tot primitieven kunnen waardetypes methoden en velden hebben. We kunnen ook interfaces implementeren en deze als generieke typen gebruiken. We kunnen de waardetypen dus vanuit twee verschillende invalshoeken bekijken:

  • Snellere objecten
  • Door de gebruiker gedefinieerde primitieven

Als extra kers op de taart kunnen we waardetypes gebruiken als generieke types zonder te boksen. Dit leidt ons rechtstreeks naar de andere grote functie van Project Valhalla: gespecialiseerde generieke geneesmiddelen.

4. Gespecialiseerde generieke geneesmiddelen

Wanneer we taalprimitieven willen genereren, gebruiken we momenteel boxed-typen, zoals Geheel getal voor int of Vlotter voor vlotter. Dit boksen creëert een extra indirecte laag, waardoor het doel van het gebruik van primitieven voor prestatieverbetering in de eerste plaats teniet wordt gedaan.

Daarom zien we veel speciale specialisaties voor primitieve typen in bestaande frameworks en bibliotheken, zoals IntStream of ToIntFunction. Dit wordt gedaan om de prestatieverbetering van het gebruik van primitieven te behouden.

Dus, gespecialiseerde generieke geneesmiddelen is een poging om de behoefte aan die "hacks" weg te nemen. In plaats daarvan streeft de Java-taal ernaar om generieke typen in te schakelen voor vrijwel alles: objectreferenties, primitieven, waardetypes en misschien zelfs leegte.

5. Conclusie

We hebben een glimp opgevangen van de veranderingen die Project Valhalla zal brengen in de Java-taal. Twee van de belangrijkste doelen zijn verbeterde prestaties en minder lekkende abstracties.

De prestatieverbeteringen worden aangepakt door objectgrafieken af ​​te vlakken en indirecte effecten te verwijderen. Dit leidt tot efficiëntere geheugenlay-outs en minder toewijzingen en garbagecollection.

De betere abstractie komt met primitieven en objecten die een meer vergelijkbaar gedrag vertonen wanneer ze worden gebruikt als generieke typen.

Een vroeg prototype van Project Valhalla, dat waardetypes introduceert in het bestaande typesysteem, heeft de codenaam LW1.

We kunnen meer informatie over Project Valhalla vinden op de bijbehorende projectpagina en JEP's:

  • Project Valhalla
  • JEP 169: Waardeobjecten
  • JEP 218: Generics over Primitive Types