2014-10-23 14 views
12

Czytałem o rzeczach JNI i nie mogę się domyślić, co się stanie, gdy wątek się rozpocznie -> wywołania AttachCurrentThread() -> wykonaj niektóre wywołania JNI -> wyjście wątku.Android JNI - Call AttachCurrentThread without DetachCurrentThread

Idealnie powinniśmy zadzwonić do DetachCurrentThread() przed wyjściem z wątku, ale jakie są implikacje, jeśli aplikacja tego nie robi? Czy spowodowałoby to wyciek pamięci lub jakiś inny problem?

+0

Zauważ, że powinieneś tylko wywołaj 'DetachCurrentThread()' jeśli podłączyłeś wątek. Zachowanie odłączające bieżący wątek, jeśli jest to wątek należący do JVM, jest niezdefiniowane. – technomage

Odpowiedz

20

Nie wywołanie DetachCurrentThread() z pewnością spowoduje wyciek pamięci; Inne konsekwencje to specyficzne dla JVM i prawdopodobnie nieistotne dla aplikacji Android, gdzie JVM zamyka się, gdy proces kończy się. Istnieje sporo C++ owijarki, które pomagają zarządzać wątek dołączeniu/odłączeniu, patrz na przykład: http://w01fe.com/blog/2009/05/c-callbacks-into-java-via-jni-made-easyier

Aktualizacja: 1000 Dzięki fadden do otwarcia oczu link; na Dalvik wątek, który wychodzi bez wywoływania DetachCurrentThread(), powoduje, że cała maszyna wirtualna i proces się zawieszają.

Oto logcat z oficjalnej emulatora, mój kod na podstawie próbki HelloJni z 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) 

Oto odpowiednia funkcja dodana do 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 !"); 
} 
+0

Nie mogę uzyskać dostępu do linku. – pree

+0

Ponadto, jeśli utworzę dużą liczbę wątków i zadzwonię do attachcurrentthread bez odłączania, wówczas wyciek pamięci jest możliwy. Jednakże, co się dzieje, jeśli jest kilka długich wątków, które kończą się bez wywoływania detachcurrentthread. Jaki byłby wpływ? Czy nie wyłączy się automatycznie po wyjściu? – pree

+0

Nie, wątki nie "automatycznie odłączają się", dopóki proces (i JVM, na Androidzie nie zdarzy się jednocześnie) zostanie zamknięty. Jak już wspomniałem, na innych platformach, gdzie JVM może przeżyć proces lub _w porównaniu, efekt może być bardziej bolesny. Ponadto wyciek może być bardzo znaczący, zależy to od tego, jak dany wątek obsługuje jego JNI. –

Powiązane problemy