Depuis Java 9, chaque nouvelle version de Java comporte des modules incubateurs, qui contiennent des fonctionnalités encore en cours de développement et qui peuvent être testées par les développeurs.
L'un de ces incubateurs est l'"Foreign-Memory Access API" (JEP 370) qui sera présenté dans ce tutoriel.
Un segment de mémoire est accessible par une adresse mémoire, qui sera vérifiée au préalable si elle fait partie de la limite de votre segment de mémoire référencé. Si vous voulez accéder à une adresse mémoire non vérifiée et qu'elle faisait partie d'un segment de mémoire que le client possédait, vous devez alors réinterpréter le décalage de l'adresse non vérifiée par rapport à l'adresse de base du segment (opération de rebasage : MemoryAddress::rebase). Si un tel segment de mémoire n'existe pas, vous pouvez alors utiliser MemorySegment::ofNativeRestricted factory à la place. Cette factory ne peut être utilisée que si la propriété JDK "foreign.restricted" n'est pas réglée sur la valeur "permit" et doit être utilisée avec précaution.
Un seul thread peut accéder (et être propriétaire) d'un certain segment de mémoire à la fois, ce qui assure une "sécurité temporelle".
Un autre thread a accès à un segment de mémoire occupé, après que le détenteur (propriétaire) du segment de mémoire ait fermé le segment. Si vous voulez accéder et modifier l'adresse de mémoire en parallèle, vous pouvez utiliser un "spliterator", qui divise un segment de mémoire en tranches. Chaque tranche est ensuite utilisée par certains threads pour effectuer des parties de la tâche complète. Le segment de mémoire ne peut pas être fermé pendant ce processus pour des raisons de sécurité.
Cette API garantit cela:
- Il peut fonctionner sur différents types de mémoire étrangère (exemple : mémoire persistante, mémoire de tas gérée, etc.)
- Elle ne porte pas atteinte à la sécurité de la "Java Runtime Machine"
- Les attributions se font de manière explicite dans votre code Java
- L'accent est mis sur la convivialité par rapport à d'autres solutions (exemple : "ByteBuffer API")
Si vous voulez compiler votre application avec cette API, vous devez alors ajouter le module "jdk.incubator.foreign".
Exemple (si vous utilisez la ligne de commande) :
javac --add-modules jdk.incubator.foreign ForeignMemoryAccess.java
Un exemple d'application avec l'API d'accès aux mémoires étrangères
package java14ForeignMemoryAccess;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryHandles;
import jdk.incubator.foreign.MemorySegment;
public class ForeignMemoryAccess {
public static void main(String[] args) {
int allocatedBlockSize = 2048;
int newValue = 1000;
VarHandle intMemoryHandle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());
try (MemorySegment accessedSegment = MemorySegment.allocateNative(allocatedBlockSize)) {
MemoryAddress addressBase = accessedSegment.baseAddress();
System.out.println("Base Address: " + addressBase);
System.out.println("Old value of accessed memory: " + intMemoryHandle.get(addressBase));
System.out.println("Set new value " + newValue + " into the accessed memory.");
intMemoryHandle.set(addressBase, newValue);
System.out.println("New value of accessed memory: " + intMemoryHandle.get(addressBase));
}
}
}
"MemoryHandles.varHandle" crée une poignée pour éditer et obtenir les valeurs d'un entier d'un certain emplacement de mémoire. "ByteOrder.nativeOrder()" nous indique d'utiliser l'ordre des octets de la RAM (mémoire) du système d'exploitation. Un objet "VarHandle" est renvoyé, qui possède également les méthodes suivantes "set" pour définir une certaine valeur à une adresse mémoire et "get" pour obtenir une valeur à partir d'une certaine adresse mémoire.
Un segment de mémoire est créé avec la fonction "MemorySegment.allocateNative", qui sera appelée dans un bloc "try-with-resources" pour s'assurer que le segment de mémoire créé est libéré à la fin du code du programme.
Vous pouvez obtenir l'adresse mémoire de base d'un certain segment de mémoire avec la méthode "baseAddress()".
Documentation:
https://download.java.net/java/GA/jdk14/docs/api/jdk.incubator.foreign/jdk/incubator/foreign/package-summary.html
En savoir plus sur cette nouvelle "Foreign-Memory Access API":
https://openjdk.java.net/jeps/383