jni 基础
Posted cyy12
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jni 基础相关的知识,希望对你有一定的参考价值。
1.
java层对应到JNI层
除了 基本类型,基本类型数组,string,throwable,class 之外,都是用jobject来代替
2.
JNIEnv是native层,一个线程作用域的,调用虚拟机方法的对象
一个线程只能用自己的JNIEnv对象(类似Threadlocal的作用于效果,和线程对象相关),如果没有
那么通过JavaVM的AttachCurrentThread 获得当前线程的JNIEnv
当当前线程结束时,调用JavaVM->DetachCurrentThread 释放对应的资源
3.
使用java对象,首先要定位到对象的jfieldID 或 jmethodID
这样可以读写/访问 对象的成员变量或成员函数
一般先用FindClass找到jclass
然后用GetMethodID(jclass,methodName,methodSig)得到jmethodID
然后用env->CallXXXXMethod(jobject,jmethodID,params...)
XXXX为返回值类型的名称
成员变量访问是类似的
SetXXXXField
GetXXXXField
XXXX是成员变量类型名称
如Object,Byte,Int。。。。
4.
jstring
env->
NewString new一个jstring对象(存储Unicode)
NewStringUTF new一个jstring对象(存储Unicode,并用UTF-8编码)
const jchar* GetStringChars(jstring string, jboolean* isCopy)
const char* GetStringUTFChars(jstring string, jboolean* isCopy) 得到一个 UTF编码的jstring的 char数组
typedef uint16_t jchar; /* unsigned 16 bits */
当在Native层通过GetStringXXXChars获取到了char* ,并使用完成后,需要手动调用ReleaseStringChars() 或 ReleaseStringUTFChars()
释放jstring对象,否则可能造成在native层导致JVM产生内存泄露
5.
函数签名
签名格式,和类型映射名称
格式:(参数类型1;参数类型2;参数类型3;。。。。;)返回值类型
类型:
基本类型,对象,int数组,对象数组
这4类
基本类型: 有一对一的类型名称映射
对象为: L/对象包名/对象名;
int数组为: [I
对象数组为: [L/对象包名/对象名;
例如 int add(float, float) 的签名为
(F;F;)I
=====
垃圾回收
java层传递的一些对象,如 thiz 可能在运行中会被垃圾回收。
所以如果需要在native层保存这个引用,需要小心在下次使用的时候,判断一下是否被回收了
native层的引用,不像java层,被虚拟机管理了强引用等方式来进行垃圾回收,也就是说
这里引用了一个地址,jvm并不知道
那么jni有3种为我们提供的引用策略,我们产生了一个引用,并且根据引用方式不同,jvm对这些引用的回收策略也不同
1.LocalRefernce 本地引用。作为函数参数传递进来,离开native函数后,这些参数可能被回收
2.GlobalRefrence 全局引用。如果不主动释放,就不会被垃圾回收。(类似java层,从GCRoot可达的强引用)
3.WeakGlobalRefrence 全局弱音引用。在jvm运行过程种可能会被回收,调用前用JNIEnv的IsSameObject 判断某个引用是否被回收了(和java层的WeakRefrece有些类似)
2.GlobalRefrence:
如果需要将一个LocalRefernce转为GlobalRefrence
env->NewGlobalRef(ref)
往往在native对象的构造函数中这样使用
然后在析构函数中用
env->DeleteGolbalRef(ref) 解除引用
1.LocalRefernce:
虽然可以等函数调用完后,会自动回收java对象,但是也可以手动立即回收
调用
env->DeleteLocalRef(jref)
原因是,如果在这个函数里new了太多临时的java对象,而不即时手动清除,可能在函数执行过程中会产生内存溢出
====
JNI中的异常
在jni中如果调用某个jnienv的函数产生了异常,
那么不会立刻中断本地函数的执行,
要等到当前函数执行完后,返回到java层后,才会抛出异常
如果在native层产生了不可恢复的异常(业务逻辑层面上的)
那么需要做一些手动的资源清除,如释放全局变量,然后等
回到java层再catch异常
jni层可以获取,修改产生的异常
ExceptionOccured 是否有异常发生
ExceptionClear 清理掉发生的异常信息
ThrowNew 向java层抛出异常
====
以上是关于jni 基础的主要内容,如果未能解决你的问题,请参考以下文章