web-dev-qa-db-fra.com

Android JNI - Appeler AttachCurrentThread sans DetachCurrentThread

J'ai lu des choses sur JNI et je n'arrive pas à comprendre ce qui se passe si un thread démarre -> appelle AttachCurrentThread () -> passe des appels JNI -> quitte le thread.

Idéalement, nous devrions appeler DetachCurrentThread () avant la fermeture du thread, cependant, quelles sont les implications si l'application ne le fait pas? Cela entraînerait-il une fuite de mémoire ou tout autre problème?

17
pree

Ne pas appeler DetachCurrentThread() provoquera définitivement une fuite de mémoire; les autres conséquences sont spécifiques à la JVM, et probablement non pertinent pour les applications Android, où la JVM s'arrête à la fin du processus. Il existe de nombreux wrappers C++ qui aident à gérer le thread Attach/Detach, voir par exemple: http://w01fe.com/blog/2009/05/c-callbacks-into-Java-via-jni- plus facile

Mise à jour: 1000 grâce à fadden pour l'ouverture des yeux link; sur Dalvik, un thread qui se termine sans appeler DetachCurrentThread(), amène l'ensemble VM et le processus se bloque.

Voici le logcat de l'émulateur officiel, mon code basé sur l'exemple HelloJni de NDK:

10-26 04:16:25.853: D/dalvikvm(1554): Trying to load lib /data/app-lib/com.example.hellojni-2/libhello-jni.so 0xb3d264f0
10-26 04:16:25.893: D/dalvikvm(1554): Added shared lib /data/app-lib/com.example.hellojni-2/libhello-jni.so 0xb3d264f0
10-26 04:16:25.893: D/dalvikvm(1554): No JNI_OnLoad found in /data/app-lib/com.example.hellojni-2/libhello-jni.so 0xb3d264f0, skipping init
10-26 04:16:26.463: D/gralloc_goldfish(1554): Emulator without GPU emulation detected.
10-26 04:16:31.033: D/threadFunction(1554): Attaching
10-26 04:16:31.173: D/threadFunction(1554): Not Detaching
10-26 04:16:31.183: D/dalvikvm(1554): threadid=11: thread exiting, not yet detached (count=0)
10-26 04:16:31.193: D/dalvikvm(1554): threadid=11: thread exiting, not yet detached (count=1)
10-26 04:16:31.193: E/dalvikvm(1554): threadid=11: native thread exited without detaching
10-26 04:16:31.193: E/dalvikvm(1554): VM aborting
10-26 04:16:31.213: A/libc(1554): Fatal signal 6 (SIGABRT) at 0x00000612 (code=-6), thread 1567 (xample.hellojni)

Voici la fonction appropriée ajoutée à hello-jni.c :

static JavaVM* jvm = 0;
static jobject activity = 0; // GlobalRef

void* threadFunction(void* irrelevant)
{
    JNIEnv* env;
    usleep(5000000);

    __Android_log_print(Android_LOG_DEBUG, "threadFunction", "Attaching");

    (*jvm)->AttachCurrentThread(jvm, &env, NULL);

    jclass clazz = (*env)->GetObjectClass(env, activity);
    jmethodID methodID = (*env)->GetMethodID(env, clazz, "finish", "()V" );
    (*env)->CallVoidMethod(env, activity, methodID);

    __Android_log_print(Android_LOG_DEBUG, "threadFunction", "Not Detaching");
//    (*jvm)->DetachCurrentThread(jvm);
}

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    (*env)->GetJavaVM(env, &jvm);
    activity = (*env)->NewGlobalRef(env, thiz);

    pthread_t hThread;
    pthread_create(&hThread, NULL, &threadFunction, NULL);
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

Une belle implémentation de cette stratégie peut être trouvée dans WebRTC git repo .

27
Alex Cohn