Algorithm

学习之前在微信读书群里分享的算法题
https://www.yuque.com/ricky-osxr4/pagerg/tmflld

Review

https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers

Tips

以下的tips 主要来自于 Review 中的 JNI 官方文档,并参考《深入理解 Android 卷一 》第二章

JavaVM 在JNI中每个进程只有一个 ,是Java虚拟机在JNI层的代表, 在JNI 全局中只有一个。

JNIEnv 每个线程就有一个,JNIEnv 是一个线程相关的结构体, 代表 Java 在本线程的运行环境;JNIEnv 几乎包含了 JNI 的所有的函数。

在 JNI 中,C 语言的表现形式为 JNINativeInterface 的结构体,而在 C++ 中则是一个 _JNIEnv 的结构,该结构体中封装 C 语言中 JNINativeInterface 的结构体。
在一些文档中 JNIEnv 也被叫做 JNI Interface 。

在JNI中的native方法中,将对象分为局部引用和全局引用。

传入 native 方法的对象都是局部的,在 native 方法结束之后就会被回收。
JNI 中的全局引用必须在显示的释放才会释放。
因为传入 native 方法的对象都是局部的,如果需要在别的地方使用该对象需要使用全局引用。在 JNI 中我们可以使用 NewGlobalRef(jobject) 通过本地引用创建全局引用。用完之后需要将全局引用使用 DeleteGlobalRef(jobject) 释放。

调用 GetStringUTFChars 时需要判断其返回值,因为调用它时会有内存自动分配,如果分配失败后,则会返回空,并且抛出 OutOfMemoryError 异常。
JNI 处理异常,不同于 Java 中的 try…catch。在 JNI 中, 发生异常,不会改变代码执行轨迹,所以,当返回 NULL,要及时返回,或马上处理异常。虽然在JNI层中产生的异常不会中断本地函数的运行,但一旦产生异常后,就只能做一些资源清理工作了(例如释放全局引用,或者ReleaseStringChars)。如果这时调用除上面所说函数之外的其他JNIEnv函数,则会导致程序死掉。

上面提到 每个线程就有一个 JNIEnv 指针。它是线程相关的。JNIEnv 只在创建它的线程有效。如果我们需要在其他线程访问JVM,那么必须先调用AttachCurrentThread 将当前线程与JVM进行关联,然后才能获得JNIEnv对象。在线程退出时时需要调用DetachCurrentThread 来解除链接。

  1. // 在 JNI native 方法中获取 JavaVM
  2. JavaVM *javaVm;
  3. env->GetJavaVM(&javaVm);
  1. // 其它的新建线程中关联 JavaVM
  2. JNIEnv *env;
  3. javaVm->AttachCurrentThread(&env, NULL);
  4. javaVm->DetachCurrentThread();

通过 JNI_CreateJavaVM 也可以创建JVM ,但是在一般情况下,一般的用户是不允许调用该方法的。调用JNI_CreateJavaVM创建JVM的线程被称为主线程,在Android 中我们是没有机会调用的。

Share

https://www.yuque.com/ricky-osxr4/xgff4o