前言
Java中有强引用、软引用、弱引用,虚引用,在JNI的使用中有局部引用(Local Reference)、全局引用(Global Reference)、弱全局引用(Weak Global Reference),本文主要介绍JNI的引用的使用
在JNI开发中比较重要的就是对内存的管理,也就是对引用的使用,否则很容易出现内存溢出,野指针等问题。java中有gc机制可以自动回收内存,在C/C++中new了一个对象,在使用结束时需要Delete,malloc一次同样需要free一次。在C/C++中还分栈空间和堆空间,所有的自动变量、函数形参都存储在栈中,自动分配(申请方式如:int i[10]),变量离开作用域后自动释放,malloc和new 都是在堆空间中,由程序员手动分配和释放,可申请占系统内存的80%
1.局部引用
在Native方法中,经常使用FindClass()、GetMethodID()、GetFieldID()来获取jclass、jmethodID、jfieldID和通过NewLocalRef产生的都是局部变量,退出Native方法时销毁,也可以调用DeleteLocalRef主动释放,不在本地函数中跨函数使用,不能跨线前使用
jclass clazz=(*env)->FindClass(env, "java/lang/String");
jmethodID jmID = (*env)->GetMethodID(env, clazz, "<init>","([BLjava/lang/String;)V");
jcharArray charArr = (*env)->NewCharArray(env, 10);
jstring str_obj = (*env)->NewObject(env, clazz, jmID, charArr);
jstring str_local_ref = (*env)->NewLocalRef(env,str_obj); // 通过NewLocalRef函数创建
2.全局引用
通过NewGlobalRef函数创建,会阻止gc回收所引用的对象,可以跨方法、跨线程使用。JVM不会自动释放,必须调用DeleteGlobalRef手动释放
///全局引用
static jclass string_clazz;
void fun_global_ref(JNIEnv *env, jobject obj){
jclass cls_string = (*env)->FindClass(env, "java/lang/String");
string_clazz = (*env)->NewGlobalRef(env,cls_string);// 通过NewGlobalRef函数创建
(*env)->DeleteGlobalRef(env,string_clazz);//手动释放
}
3.弱全局引用
通过NewWeakGlobalRef函数创建,不会阻止gc回收所引用的对象,可以跨方法、跨线程使用。引用不会自动释放,在JVM认为应该回收它的时候(比如内存紧张的时候)进行回收而被释放。或调用DeleteWeakGlobalRef手动释放。
///全局弱引用
static jclass weak_string_clazz;
void fun_weak_global_ref(JNIEnv *env, jobject obj){
jclass cls_string = (*env)->FindClass(env, "java/lang/String");
weak_string_clazz = (*env)->NewWeakGlobalRef(env,cls_string);// 通过NewWeakGlobalRef函数创建
(*env)->DeleteWeakGlobalRef(env,weak_string_clazz);//手动释放
}
4.野指针
“野指针”不是NULL指针,是指向“垃圾”内存的指针,if很容易判断是否是一个空指针,但是if无法判断一个指针是正常指针还是“野指针”
“野指针”形成的原因
- 指针变量没有被初始化
- 指针p被free或者delete之后,没有置为NULL,误以为p是个合法的指针
下面是一个野指针的例子
///野指针
JNIEXPORT jstring JNICALL Java_clz_Register_testWildPointer(JNIEnv *env, jobject obj) {
jcharArray elemArray;
char *chars = "c";
jstring j_str = NULL;
static jclass clazz = NULL;
static jmethodID cid_string = NULL;
///1 缓存clazz 错误的缓存
if (clazz == NULL) {
clazz = (*env)->FindClass(env, "java/lang/String");
if (clazz == NULL) {
return NULL;
}
}
///缓存String的构造方法ID
if (cid_string == NULL) {
cid_string = (*env)->GetMethodID(env, clazz, "<init>", "([C)V");
if (cid_string == NULL) {
return NULL;
}
}
elemArray = (*env)->NewCharArray(env, strlen(chars));
(*env)->SetCharArrayRegion(env, elemArray, 0, strlen(chars), (const jchar *) chars);
j_str = (*env)->NewObject(env, clazz, cid_string, elemArray);
(*env)->DeleteLocalRef(env, elemArray);
(*env)->DeleteLocalRef(env, clazz);
elemArray=NULL;
// clazz=NULL;
return j_str;
}
上面的代码在ja va中调用一次testWildPointer不会报错,当调用testWildPointer第二次时 就会报错,原因是第一次调用testWildPointer,DeleteLocalRef掉clazz后,clazz没有被置为NULL,就成了一个野指针,他是不为NULL的,所以并没有走FindClass获取,这里两种办法都可以报错,clazz==NULL或者变量声明的static关键字去掉
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。