JNI_OnLoad和JNI_OnUnload
jint JNI_OnLoad(JavaVM *vm, void *reserved);
JNI_OnLoad
when the native library is loaded (for example, through
System.loadLibrary
).
JNI_OnLoad
must return the JNI version needed by the native library.
In order to use any of the new JNI functions, a native library must export a JNI_OnLoad
function that returns JNI_VERSION_1_2
. If the native library does not export a JNI_OnLoad
function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1
. If the VM does not recognize the version number returned by JNI_OnLoad
, the native library cannot be loaded.
Exported from native libraries that contain native method implementation.
In order to use the JNI functions introduced in J2SE release 1.2, in addition to those that were available in JDK/JRE 1.1, a native library must export a JNI_OnLoad
function that returns JNI_VERSION_1_2
.
In order to use the JNI functions introduced in J2SE release 1.4, in addition to those that were available in release 1.2, a native library must export a JNI_OnLoad
function that returns JNI_VERSION_1_4
.
If the native library does not export a JNI_OnLoad
function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1
. If the VM does not recognize the version number returned by JNI_OnLoad
, the native library cannot be loaded.
JNI_OnUnload
void JNI_OnUnload(JavaVM *vm, void *reserved);
JNI_OnUnload
when the class loader containing the native library is garbage collected. This function can be used to perform cleanup operations. Because this function is called in an unknown context (such as from a finalizer), the programmer should be conservative on using Java VM services, and refrain from arbitrary Java call-backs.
Note that JNI_OnLoad
and JNI_OnUnload
are two functions optionally supplied by JNI libraries, not exported from the VM.
从官网中,可以了解到JNI_OnLoad()主要的几点:
System.loadLibrary
)第一个参数是JavaVM,它是虚拟机在JNI层的代表,从JDK / JRE 1.2开始,不支持在单个进程中创建多个VM。那么在整个进程中javaVM只有一个,如果后面要使用,可以保存下来。
JavaVM有什么作用呢?
JNI接口指针(JNIEnv
)仅在当前线程中有效。如果另一个线程需要访问Java VM,它必须先调用它AttachCurrentThread()
自己附加到VM并获得一个JNI接口指针(JNIEnv)。一旦连接到虚拟机,本地线程就像在本地方法内运行的普通Java线程一样工作。本地线程保持连接到VM直到它调用DetachCurrentThread()
分离自己。连接到VM的本地线程在退出之前必须调用DetachCurrentThread()以分离它自己。如果调用堆栈上有Java方法,则线程无法自行分离。简而言之调用JavaVM的AttachCurrentThread函数,就可得到这个线程的JNIEnv结构体。这样就可以在后台线程中回调Java函数了。另外,后台线程退出前,需要调用JavaVM的DetachCurrentThread函数来释放对应的资源。
比如:获取java中的类,以便后面调用java中的函数
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
return -1;
}
const char *packet = "com/xxx/xxx/jniClass/Packet";clsPacket = jniGlobalRef(env, jniFindClass(env, packet));
当GC回收了加载这个库的ClassLoader时,该函数被调用,该函数可用于执行清理操作。由于这个函数是在未知的上下文中调用的,所以程序员在使用Java VM服务时应该保持谨慎,并且避免任意的Java回调
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK)
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
else {
(*env)->DeleteGlobalRef(env, clsPacket);
(*env)->DeleteGlobalRef(env, clsRR);
}