Copie et épinglage

La récupération de place peut, à tout moment, décider de compacter le tas collecté. Le compactage implique de transférer physiquement des objets d'une adresse vers une autre. Une référence locale ou globale JNI peut faire référence à ces objets. Pour que le compactage s'effectue correctement, les références JNI ne sont pas des pointeurs directs vers le tas. Au moins un niveau d'indirection isole le code natif du déplacement des objets.

Si une méthode native doit obtenir une adressabilité directe à l'intérieur d'un objet, la situation est plus complexe. La nécessité d'adresser directement, ou d'épingler, le tas apparaît généralement lorsqu'un accès rapide et partagé à de grands tableaux de primitives s'impose. Un tampon d'écran est un exemple. Dans ce cas, une section importante de JNI peut être utilisée, ce qui impose d'autres conditions au programmeur, tel que spécifié dans la description JNI de ces fonctions. Consultez la spécification JNI pour plus d'informations.

  • GetPrimitiveArrayCritical renvoie l'adresse de segment de mémoire directe d'un tableau Java™ , en désactivant la récupération de place jusqu'à ce que le ReleasePrimitiveArrayCritical correspondant soit appelé.
  • GetStringCritical retourne l'adresse de tas directe d'une instance java.lang.String en désactivant la récupération de place jusqu'à ce que la fonction ReleaseStringCritical soit appelée.

Toutes les autres interfaces Get<PrimitiveType>ArrayElements renvoient une copie qui n'est pas affectée par le compactage.

Si vous utilisez la politique de récupération de place équilibrée (balanced), les formes *Critical des appels peuvent ne pas renvoyer un pointeur direct dans le tas, ce qui est alors reflété par le drapeau (booléen) isCopy. Ce comportement est dû à une représentation interne de tableaux plus grands dans lesquels les données ne sont pas forcément séquentielles. En général, un tableau dont l'espace de stockage est inférieur à 1/1000ème du tas est renvoyé sous forme de pointeur direct.

Utilisation du drapeau isCopy

Les fonctions JNI Get<Type> indiquent un paramètre de sortie pass-by-reference (jboolean * isCopy) qui permet à l'appelant de déterminer si un appel JNI donné renvoie l'adresse d'une copie ou l'adresse de l'objet réservé dans le tas.

Les fonctions Get<Type> et Release<Type> sont les suivantes :

  • GetStringChars et ReleaseStringChars
  • GetStringCritical et ReleaseStringCritical
  • GetStringUTFChars et ReleaseStringUTFChars
  • Get<PrimitiveType>ArrayElements et Release<PrimitiveType>ArrayElements
  • GetPrimitiveArrayCritical et ReleasePrimitiveArrayCritical

Si vous passez une adresse non null comme paramètre de isCopy, la fonction JNI met à JNI_TRUE la valeur du jboolean à cette adresse, si l'adresse retournée est celle d'une copie des éléments de tableau, et à JNI_FALSE si l'adresse pointe directement vers l'objet épinglé dans le tas.

La MV J9 retourne toujours une copie, sauf pour les fonctions importantes. La copie évite de surcharger le récupérateur de place, car les objets épinglés ne peuvent pas être compactés et compliquent la défragmentation.

Pour éviter les fuites, vous devez :

  • Gérez vous-même la mémoire de copie à l'aide des fonctions Get<Type>Region et Set<Type>Region.
  • Assurez-vous que vous libérez des copies effectuées par une fonction Get<Type> en appelant la fonction Release<Type> correspondante lorsque la copie n'est plus nécessaire.

Utilisation de l'indicateur de mode

Lorsque vous appelez la commande Release<Type>ArrayElements, le dernier paramètre est un indicateur de mode. L'indicateur de mode est utilisé pour éviter une copie inutile dans le segment de mémoire Java lors de l'utilisation d'un tableau copié. Ce drapeau est ignoré si vous travaillez avec un tableau qui a été épinglé.

Vous devez appeler Release<Type> une fois pour chaque appel Get<Type>, quelle que soit la valeur du paramètre isCopy. Cette étape est nécessaire, car l'appel de Release<Type> supprime les références locales JNI qui pourraient autrement empêcher la récupération de place.

Les valeurs possibles de l'indicateur de mode sont :
0
Mettez à jour les données sur le segment de mémoire Java. Libère l'espace utilisé par la copie.
JNI_COMMIT
Mettez à jour les données sur le segment de mémoire Java. Ne libère pas l'espace utilisé par la copie.
JNI_ABORT
Ne mettez pas à jour les données sur le segment de mémoire Java. Libère l'espace utilisé par la copie.

L'indicateur de mode '0' est le choix le plus sûr pour l'appel Release<Type>. Le tas est mis à jour avec la copie et il n'existe aucune fuite, que la copie des données ait changé ou non.

Pour éviter de recopier une copie non modifiée, utilisez la valeur de mode JNI_ABORT. Si vous modifiez le tableau retourné, vérifiez l'indicateur isCopy avant d'utiliser la valeur de mode JNI_ABORT pour "annuler" les modifications. Cette étape est nécessaire, car une JVM qui épingle quitte le tas dans un état différent de celui d'une JVM qui copie.

Utilisation générique des indicateurs isCopy et de mode

Voici une méthode d'utilisation générique des indicateurs isCopy et de mode. Elle fonctionne avec toutes les JVM et permet de valider les modifications et d'éviter les fuites.

Pour utiliser les indicateurs de manière générique :
  • N'utilisez pas l'indicateur isCopy. Passez null ou 0.
  • Mettez toujours l'indicateur de mode à zéro.

Une utilisation complexe de ces indicateurs est nécessaire uniquement pour l'optimisation. Si vous utilisez la méthode générique, vous devez toujours tenir compte de l'optimisation. Voir Synchronisation.