Présentation des références d'objets JNI
Les informations d'implémentation relatives à la manière dont le récupérateur de place recherche la référence d'un objet ne sont pas détaillées dans la spécification JNI. L'interface JNI spécifie à la place un comportement requis fiable et prévisible.
Références locales et globales
Les références locales sont limitées à leur cadre de pile et unité d'exécution de création et automatiquement supprimées à la fin de l'exécution de leur cadre de pile de création. Les références globales permettent au code natif de promouvoir une référence locale sous une forme utilisable par le code natif dans une unité d'exécution connectée à la JVM.
Références globales et fuites de mémoire
Les références globales ne sont pas supprimées automatiquement et le programmeur doit traiter la gestion de la mémoire. Chaque référence globale établit une racine pour le référent et rend l'ensemble de sa sous-arborescence accessible. Par conséquent, chaque référence globale créée doit être libérée pour éviter les fuites de mémoire.
A terme, les fuites dans les références globales conduisent à une exception par manque de mémoire. Ces erreurs peuvent être difficiles à éliminer, notamment si vous ne gérez par les exceptions JNI. Voir Traitement des exceptions.
- NewWeakGlobalRef
- DeleteWeakGlobalRef
Références locales et fuites de mémoire
La récupération de place automatique des références locales qui ne se trouvent plus dans la portée évite les fuites de mémoire dans la plupart des cas. Cette récupération de place automatique se produit lorsqu'une unité d'exécution native revient à Java (méthodes natives) ou se déconnecte de la machine virtuelle Java (API d'appel). Des fuites mémoire provoquées par les références locales sont possibles si la récupération automatique n'a pas lieu. Une fuite de mémoire peut se produire si une méthode native ne revient pas dans la JVM ou qu'un programme qui utilise l'API d'appel ne se déconnecte pas de la JVM.
Reportez-vous au code suivant dans lequel le code natif crée des références locales dans une boucle :
while ( <condition> )
{
jobject myObj = (*env)->NewObject( env, clz, mid, NULL );
if ( NULL != myObj )
{
/* we know myObj is a valid local ref, so use it */
jclass myClazz = (*env)->GetObjectClass(env, myObj);
/* uses of myObj and myClazz, etc. but no new local refs */
/* Without the following calls, we would leak */
(*env)->DeleteLocalRef( env, myObj );
(*env)->DeleteLocalRef( env, myClazz );
}
} /* end while */Bien que les nouvelles références locales remplacent les variables myObj et myClazz dans la boucle, chaque référence locale est conservée dans l'ensemble racine. Ces références doivent être supprimées explicitement par l'appel DeleteLocalRef. Sans les appels DeleteLocalRef , les références locales sont divulguées jusqu'à ce que l'unité d'exécution soit renvoyée à Java ou déconnectée de la machine virtuelle Java.
Références globales faibles JNI
Les références globales faibles sont un type spécial de référence globale. Elles peuvent être utilisées dans n'importe quelle unité d'exécution et entre des appels de fonctions natifs, mais elles ne font pas office de racines de récupération de place. Le récupérateur de place dispose d'un objet référencé par une référence globale faible à tout moment si l'objet n'a pas une référence forte autre part.
Utilisez les références globales faibles avec précaution. Si la place de l'objet référencé par une référence globale faible est récupéré, la référence devient une référence null. Une référence null peut être utilisée en toute sécurité avec un sous-ensemble des fonctions JNI. Pour déterminer si la place d'une référence globale faible a été récupérée, utilisez la fonction IsSameObject JNI pour comparer la conférence à la valeur null.
L'appel de la plupart des fonctions JNI avec une référence globale faible présente un risque, même si vous avez déterminé que la référence n'est pas null, car la référence globale faible peut devenir une référence null après l'avoir testée ou même au cours de l'exécution de la fonction JNI. A la place, promouvez toujours une référence globale faible comme référence forte avant de l'utiliser. Vous pouvez promouvoir une référence globale faible en utilisant la fonction JNI NewLocalRef ou NewGlobalRef.
Les références globales faibles utilisent de la mémoire et doivent être libérées avec la fonction JNI DeleteWeakGlobalRef lorsqu'elles ne sont plus utiles. Si vous ne libérez pas les références globales faibles, vous générez une fuite de mémoire lente et finalement des exceptions de manque de mémoire.
Pour des informations et les avertissements sur l'utilisation des références globales faibles JNI, consultez la spécification JNI.
Gestion des références JNI
Il existe un ensemble de règles indépendantes de la plateforme pour la gestion des références JNI.
Ces règles sont les suivantes :
- Les références JNI sont valides uniquement dans les unités d'exécution connectées à une JVM.
- Une référence locale valide JNI dans le code natif doit être obtenue :
- Comme paramètre dans le code natif
- Comme valeur de retour d'un appel de fonction JNI
- Une référence globale JNI valide doit être obtenue d'une autre référence JNI valide (globale ou locale) en appelant NewGlobalRef ou NewWeakGlobalRef.
- La référence de valeur null est toujours valide et peut être utilisée à la place des références JNI (globales ou locales).
- Les références locales JNI sont valides uniquement dans l'unité d'exécution qui les crée et restent valides uniquement tant que leur cadre de création reste dans la pile.
- Le remplacement d'une référence locale ou globale dans la mémoire native par une valeur null ne supprime pas la référence du groupe de racines. Utilisez la fonction Delete*Ref JNI appropriée pour la supprimer des groupes de racines.
- La plupart des fonctions JNI (telles que FindClass et NewObject) retournent une valeur null si une exception est en attente. La comparaison de la valeur retournée à la valeur null de ces appels est sémantiquement équivalente à un appel de la fonction JNI ExceptionCheck. Consultez la spécification JNI pour plus d'informations.
- N'utilisez jamais une référence locale JNI après l'exécution de son cadre de création dans tous les cas. Il est dangereux de stocker une référence locale JNI dans une mémoire statique de processus.