OpenJDK Projet Lilliput
Contexte
Avez-vous passé ce tweet ? ou cette information ?
Lilliput est un nouveau projet qui vient d’être créé au sein d’OpenJDK. Il démarre tout juste donc il n’y a pas encore d’information sur le wiki.
Néanmoins, le but a été défini lors de la proposition de création du projet. L’objectif est de travailler sur la taille mémoire des instances, notamment sur la partie d’en-tête.
Situation actuelle
Regardons, pour la VM Hotspot 64 bits, l’en-tête d’une instance est actuellement de 128 bits en deux parties :
-
1er bloc de 64 bits qui est appelé mark (ou lock-word) : cette zone a plusieurs utilités (Ramasse-miette générationnel, verrou de synchronisation, hascode…)
-
2e bloc de 64 bits qui est le pointeur vers la classe : cette zone permet de référencer la classe correspond à l’instance.
Voici la représentation :
+------------------+
| mark (Lock-word) |
+------------------+
| Class pointer |
+------------------+
| Field 1 |
+--------+---------+
| Field 2| Field 3 |
+--------+---------+
| etc |
Nous pouvons visualiser l’usage mémoire d’une instance en utilisant l’outil JOL (Java Object Layout) d' OpenJDK. Donc, nous allons ajouter la dépendance Maven vers JOL dans notre pom.xml.
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.15</version>
</dependency>
Nous allons commencer par écrire une classe très simple sans attribut.
public class A {
// pas d'attributs
}
Ensuite, nous écrivons du code pour instancier notre classe, puis pour visualiser l’usage mémoire avec JOL.
final A a = new A();
// Utilisation de JOL
ClassLayout layout = ClassLayout.parseInstance(a);
out.println(layout.toPrintable());
Nous obtenons le résultat suivant :
fr.lbenoit.package.demo.test.MaClasse$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0x08011b60
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Pour l’en-tête contenant le pointeur de la classe (2e ligne), vous pourriez me dire que la taille est seulement de 4 octets et non de 8 octets. Oui et c’est normale, car j’utilise un JDK 11 et les pointeurs de classes sont compressés par défaut.
Néanmoins, avec les histoires d’alignement mémoire, la taille de l’instance reste à 16 octets.
Au niveau de la JVM, nous pouvons désactiver cette compression avec l’option -XX:-UseCompressedClassPointers
, nous obtenons le résultat attendu :
org.openjdk.jol.samples.JOLSample_15_IdentityHashCode$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 8 (object header: class) 0x00007f2ee931c3b8
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
La taille est bien de 16 octets, soit 128 bits.
Maintenant, nous pouvons compléter notre classe avec deux attributs :
-
attribut bool de type
boolean
-
attribut obj de type
Objet
Nous obtenons le code suivant :
public class A {
boolean bool;
Object obj;
}
Après les en-têtes de l’instance, nous allons pouvoir visualiser les attributs de la classe. Voici le résultat en utilisant toujours l’outil JOL:
fr.lbenoit.package.demo.test.MaClasse$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) N/A
8 4 (object header: class) N/A
12 1 boolean A.bool N/A
13 3 (alignment/padding gap)
16 4 java.lang.Object A.obj N/A
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
En complément, pour les tableaux, nous avons la même représentation avec un champ supplémentaire avec la taille. Cela donne la représentation suivante :
+------------------+
| mark (Lock-word) |
+------------------+
| Class pointer |
+------------------+
| Array-Length |
+--------+---------+
| Elem 1 | Elem 2 |
+--------+---------+
| etc |
Projet Lilliput
Donc, les objectifs sont les suivants :
-
réduire l’en-tête à 64 bits, voir potentiellement dans un second objectif 32 bits.
-
rendre l’en-tête des instances plus flexibles.
En reduisant la taille de l’entête d’une instance, cela diminuera la mémoire utilisée et la pression associée lors de forte allocation.
Donc, nous aurons les intérêts suivants :
-
Réduction de l’usage de tas (heap)
-
Taux d’allocation plus haut
-
Réduction de l’activité du ramasse-miette
Roman Kennke est leader du projet (auteur du tweet en début de billet). De plus, Rémi Forax fait parti du projet en tant que contributeur.
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads