Mantener una referencia global al entorno JNIEnv

3 minutos de lectura

avatar de usuario
weston

estoy guardando JNIEnv en un global para poder llamar a métodos java estáticos más tarde. Pero, ¿es necesario almacenar un puntero global a la JNIEnvcomo lo haría con cualquier otro objeto Java, o es un caso especial que no requiere esto.

JNIEnv* globalEnvPointer;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
}

Editar

Soy un poco tonto aquí, todos los métodos que usaré globalEnvPointerse invocan dentro de mi init porque mi init es en realidad mi c del programa main método, que no volverá hasta el final del programa. Tampoco estoy usando otros hilos en el programa c. Creo que esto simplifica la respuesta.

JNIEnv* globalEnvPointer;

[JNICALL etc] void main(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
   someMethod();
}

void someMethod()
{
   //use globalEnvPointer here
}

avatar de usuario
mamá

No puede almacenar en caché el JNIEnv puntero. Lee sobre ello aquí:

El puntero de la interfaz JNI (JNIEnv) solo es válido en el subproceso actual. Si otro subproceso necesita acceder a la VM de Java, primero debe llamar a AttachCurrentThread() para adjuntarse a la VM y obtener un puntero de interfaz JNI. Una vez conectado a la máquina virtual, un subproceso nativo funciona como un subproceso Java normal que se ejecuta dentro de un método nativo. El subproceso nativo permanece adjunto a la máquina virtual hasta que llama a DetachCurrentThread() para desconectarse.

Lo que puedes hacer es almacenar en caché el JavaVM puntero en su lugar.

static JavaVM *jvm;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   jint rs = (*env)->GetJavaVM(env, &jvm);
   assert (rs == JNI_OK);
}

Y luego cuando lo necesites entonces JNIEnv puntero de un contexto donde no se le da hacer esto:

void someCallback() {
    JNIEnv *env;
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
    assert (rs == JNI_OK);
    // Use the env pointer...
}

Pero cada vez que llama a un método nativo desde Java, se proporciona el puntero env para usar:

JNIEXPORT jint JNICALL Java_package_Class_method(JNIEnv *env, jobject obj) {
    // just use the env pointer as is.
}

  • Es todo un hilo, ¿eso hace alguna diferencia? es decir, mi init se llama en el mismo hilo que luego llamará a los métodos estáticos de Java.

    – Weston

    14 de septiembre de 2012 a las 9:27

  • Podrías, pero ¿no es un poco feo? En mi opinión, almacenar datos temporales en variables globales para utilizarlos con otros métodos es un antipatrón.

    – mamá

    14 de septiembre de 2012 a las 9:49

  • Sí, estoy de acuerdo, pero estoy tratando de tomar una gran c fuente base y reescriba más de 100 métodos de ensamblaje en Java (como someCallback). Estamos hablando de unos pocos miles de lugares donde se realizan invocaciones. Además, la misma base de origen aún debe compilarse para su objetivo original, por lo que pasar JNIEnv around es en realidad la solución fea. Gracias por todos los consejos, los tendré en cuenta si necesito usar hilos.

    – Weston

    14/09/2012 a las 10:25


  • No crearía mi propia función de inicio si ya existe JNI_OnLoad, que pasa JavaVM.

    – DanielB

    17 mayo 2017 a las 12:58

  • @maba: el OP podría necesitar una función de inicio separada, pero tal vez tampoco conozca la existencia de JNI_OnLoad. Simplemente extiende la respuesta. No se trata de una crítica, sino de una pequeña sugerencia amistosa de extensión. No escribo mi propia respuesta, porque creo que tu respuesta ya es buena y deberías obtener los puntos. Sin embargo, también piense en otras personas que leen su respuesta, no solo en el OP y hay personas con experiencia y sin experiencia debajo de ellos.

    – DanielB

    1 de septiembre de 2017 a las 17:16

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad