javaandroidc++java-native-interface

Why JNI env (JNI interface pointer) is thread specific?


Two doubts from JNI Design Overview docs:

The JNI interface pointer is only valid in the current thread. A native method, therefore, must not pass the interface pointer from one thread to another. A VM implementing the JNI may allocate and store thread-local data in the area pointed to by the JNI interface pointer.

The JNI env(JNI interface pointer) is just a pointer to a pointer that makes JNI functions available through it.

Then why each thread requires its own JNIEnv? I just want the JNIEnv to access the JNI Functions, which I believe will remain the same across every thread. why should I care to fetch JNIEnv for each thread specifically?

also one vague question, what does these lines mean here:

the VM may support two JNI function tables:

one performs thorough illegal argument checks, and is suitable for debugging;

the other performs the minimal amount of checking required by the JNI specification, and is therefore more efficient.

Does it mean that Java VM can provide two versions of JNIEnv(pointing to two different function tables) to the consumer, with one performing thorough argument checks or does it mean internally it uses two function tables, I guess it means the later but as a consumer can take any advantage of thorough illegal arguments checks functionality.

Link: https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp16696


Solution

  • Your first quote literally states

    A VM implementing the JNI may allocate and store thread-local data in the area pointed to by the JNI interface pointer.

    Some examples of what a JVM might stuff there:

    By making the local reference table thread-local the JVM can forego many of the normal concurrency protections it has for global references and it can clean up really quickly after a native method call.

    As for your second question: yes, the JVM has two separate function tables which are chosen depending on -Xcheck:jni or the Android equivalent of strict JNI checking.

    Finally, the JNI was designed in an time where it was plausible that a single process might have multiple JVMs created, in which case you might attach different threads to different JVMs or even attach the same thread to multiple JVMs! Today, however, it is probably safe to assume that every thread receives the same set of function pointers, but why gamble with that? There might be JVMs out there that hand out JNIEnvs with extra restrictions or vendor-specific extensions...