Algorithm
学习之前在微信读书群里分享的算法题
https://www.yuque.com/ricky-osxr4/pagerg/tmflld
Review
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
来解除链接。
// 在 JNI native 方法中获取 JavaVM
JavaVM *javaVm;
env->GetJavaVM(&javaVm);
// 其它的新建线程中关联 JavaVM
JNIEnv *env;
javaVm->AttachCurrentThread(&env, NULL);
javaVm->DetachCurrentThread();
通过 JNI_CreateJavaVM
也可以创建JVM ,但是在一般情况下,一般的用户是不允许调用该方法的。调用JNI_CreateJavaVM
创建JVM的线程被称为主线程,在Android 中我们是没有机会调用的。