Utilizar el Java Native Interface (JNI)

Hasta ahora, hemos utilizado tipos de datos como jobject, jclass, y jstring para denotar referencias a objetos Java. Sin embargo, el JNI crea referencias para todos los argumentos pasados a los m�todos nativos, as� como de los objetos devueltos desde funciones JNI.

Las referencias sirven para evitar que los objetos Java sean recolectados por el recolector de basura. Por defecto, el JNI crea referencias locales porque �stas aseguran que la M�quina Virtual pueda liberar eventualmente los objetos Java. Las referencias locales se vuelven inv�lidas cuando la ejecuci�n del programa retorna desde el m�todo nativo en el que se cre�. Por lo tanto, un m�todo nativo no deber�a almacencer una referencia local y esperar utilizarla en llamadas subsecuentes.

Por ejemplo, el siguiente programa, que es una variaci�n del m�todo nativo de FieldAccess.c, err�neamente captura el ID del campo Java para no tener que buscarlo repetidamente bas�ndose en el nombre y la firma en cada llamada.

/* This code is illegal */
static jclass cls = 0;
static jfieldID fld;

JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
  ...
  if (cls == 0) {
    cls = (*env)->GetObjectClass(env, obj);
    if (cls == 0)
      ... /* error */
    fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  }
  ... /* access the field using cls and fid */
}

Este c�digo es ilegal porque la referencia local devuelta desde GetObjectClass es s�lo v�lida antes de que retorne el m�todo nativo. Cuando una aplicaci�n Java llama al m�todo nativo Java_FieldAccess_accessField una segunda vez, el m�todo nativo trata de utilizar una referencia no v�lida. Esto acabar� en un resultado err�neo o un cuelgue de la M�quina Virtual.

Se puede solucionar este problema creando una referencia global. Una referencia global permanecer� v�lida hasta que se liber� expl�citamente. El siguiente c�digo reescribe el programa anterior y utiliza correctamente la referencia global para capturar el ID del objeto.

/* This code is OK */
static jclass cls = 0;
static jfieldID fld;

JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
  ...
  if (cls == 0) {
    jclass cls1 = (*env)->GetObjectClass(env, obj);
    if (cls1 == 0)
      ... /* error */
    cls = (*env)->NewGlobalRef(env, cls1);
    if (cls == 0)
      ... /* error */      
    fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  }
  ... /* access the field using cls and fid */
}

Una referencia global evita que la Maquina Virtual descargue la clase Java, y por lo tanto tambi�n asegura que el ID del campo permanezca v�lido, como se explic� en Acceder a Campos Java. Sin Embargo, el c�digo nativo debe llamar a DeleteGlobalRefs cuando no necesite acceder m�s a la referencia global. De otro modo, la M�quina Virtual nunca descargar� el objeto correspondiente.

En la mayor�a de los casos, los programadores nativos relegan en la VM la liberaci�n de las referencias locales despu�s de retornar del m�todo nativo. Sin embargo, en ciertas situaciones, el c�digo nativo podr�a necesitar llamar a la funci�n DeleteLocalRef para borrar expl�citamente una referencia local. Estas situaciones son.

  • Podr�amos saber que estamos manteniendo la �nica refencia a un objeto Java de gran tama�o y no queremos esperar hasta que el m�todo nativo retorne antes de que el recolector de basura reclame ese objeto. Por ejemplo, en el siguiente fragmento de c�digo, el colector de basura podr�a liberar el objeto Java referenciado por lref cuando est� dentro de lengthyComputation.
      lref = ...            /* a large Java object */
    
      ...                   /* last use of lref */
      (*env)->DeleteLocalRef(env, lref);
    
      lengthyComputation(); /* may take some time */
    
      return;               /* all local refs will now be freed */
    }
    
  • Podr�amos necesitar crear un gran n�mero de referencias locales en una s�la llamada a un m�todo nativo. Esto podr�a resultar en una sobrecarga en la tabla de referencias locales del JNI. Es una buena idea borrar aquellas referencias locales que no se van a necesitar. Por ejemplo, en el siguiente fragmento de c�digo, el c�digo nativo itera a trav�s de un array potencialmente grande arr que contiene strings Java. Despu�s de cada iteraci�n, el programa puede liberar la referencia local del elemento string.
      for(i = 0; i < len; i++) {
        jstring jstr = (*env)->GetObjectArrayElement(env, arr, i);
        ...                                /* processes jstr */ 
        (*env)->DeleteLocalRef(env, jstr); /* no longer needs jstr */
      }
    

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO