NDK开发学习笔记(3):JNI访问数组、引用、异常处理、缓存策略
2017-08-13 22:26
639 查看
/* * jni访问java中的数组 */ JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_giveArray (JNIEnv *env, jobject jobj, jintArray arr) { int compare(jint *a, jint *b);//声明方法,可以在函数的内部 //jintArray->jint * jint *elemts = (*env)->GetIntArrayElements(env, arr, NULL); if (elemts == NULL) { return; } //获取数组的长度 int len = (*env)->GetArrayLength(env, arr); qsort(elemts, len, sizeof(jint), compare);//c的库中提供的排序方法 //释放可能的内存;将JNI修改的数据重新写回原来的内存,所以如果不调用此方法的话,java中的打印的数据还是没有排序的 (*env)->ReleaseIntArrayElements(env, arr, elemts, JNI_COMMIT); } int compare(jint *a, jint *b) { return *a - *b; } /* * 访问引用数据类型的数组 *通过jni实现一个数组并返回给java使用 */ JNIEXPORT jobjectArray JNICALL Java_com_mei_test_jni_JniTest_initStringArray (JNIEnv *env, jobject jobj, jint size ) { //1、创建jobjectArray jobjectArray result; jclass jclz; jint i; jclz = (*env)->FindClass(env, "java/lang/String"); if (jclz == NULL) { return NULL; } result = (*env)->NewObjectArray(env, size, jclz, jobj); if (result == NULL) { return NULL; } //2、赋值 for ( i = 0; i < size; i++) { //c字符串 char * c_str = (char*)malloc(256); memset(c_str, 0, 256); //c语言,将int转换成为char sprintf(c_str, "hello num:%d\n", i); //C String->jstring jstring str = (*env)->NewStringUTF(env, c_str); if (str == NULL) { return NULL; } //将jstring赋值给数组 (*env)->SetObjectArrayElement(env, result, i, str); free(c_str); c_str = NULL; //(*env)->DeleteGlobalRef(env, str); } //3、返回 return result; } //JNI引用 //局部引用 //全局引用 //弱全局引用 /* * 局部引用:定义方式多样 * 创建方式:有很多,如:FindClass,NewObject,GetObjectClass,NewCharArray....NewLocalRef()等等都是创建局部引用的方式。 * 产生了一个引用类型的操作或方法,都可以认为是创建了一个局部引用,所以FindClass也是一个创建局部引用的操作 * 释放局部引用的方式:1、方法调用完JVM会自动释放;2、通过DeleteLocalRef手动释放。 * 注意:局部引用不能在多线程中使用, */ JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_localRef (JNIEnv *env, jobject jobj) { int i = 0; for ( i = 0; i < 5; i++) { jclass cls = (*env)->FindClass(env, "java/util/Date");//这个也是一个局部引用 jmethodID jmid = (*env)->GetMethodID(env, cls, "<init>", "()V"); //(*env)->NewObject(env, cls, jmid)这个就是创建了一个Date类型的局部引用 jobject obj = (*env)->NewObject(env, cls, jmid); //使用这个引用 //释放引用 /* *在JNI中,会创建一个布局引用表,其大小为512,即能存储512个局部引用,如果我们没有及时动释放的话, *如果在某一时间创建的局部引用超过了512个,就会造成内存溢出。因此即使JVM会自动释放内存空间,我们还是要自己手动释放,避免内存溢出 */ (*env)->DeleteLocalRef(env, cls); (*env)->DeleteLocalRef(env, obj); } } /* * 全部引用 * 创建方式:NewGlobalRef方法式创建全局引用的唯一方式 * 释放方式:通过DeleteGlobalRef方法释放全局引用 * 优点:可以跨线程,垮方法使用 */ jstring global_str; JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_createGlobalRef (JNIEnv *env, jobject jobj) { jobject obj = (*env)->NewStringUTF(env, "JNI is intersting"); global_str = (*env)->NewGlobalRef(env, obj);//这就创建了一个全局引用 } JNIEXPORT jstring JNICALL Java_com_mei_test_jni_JniTest_getGlobalRef (JNIEnv *env, jobject jobj) { return global_str; } JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_deleteGlobalRef (JNIEnv *env, jobject jobj) { (*env)->DeleteGlobalRef(env, global_str); } /* * 弱全局引用 * 创建方式:NewWeakGlobalRef方法式创建弱全局引用的唯一方式 * 释放方式:自动释放,无需手动释放 * 优点:弱全局引用不会阻止GC,即不会发生内存泄露,不会释放不掉,当内存不足时,优先被释放 */ jclass g_weak_cls; JNIEXPORT jstring JNICALL Java_com_mei_test_jni_JniTest_createWeakRef (JNIEnv *env, jobject jobj){ jclass cls_string = (*env)->FindClass(env, "java/lang/String"); g_weak_cls = (*env)->NewWeakGlobalRef(env, cls_string); return g_weak_cls; } /* * JNI异常处理 */ JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_exception (JNIEnv *env, jobject jobj) { jclass cls = (*env)->GetObjectClass(env, jobj); jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");//java中没有字段key,所以会报错 jthrowable exception = (*env)->ExceptionOccurred(env); if (exception !=NULL)//说明发生了异常 { jclass newExc; //发送一个异常,让java可以捕捉到 (*env)->ExceptionClear(env);//清空JNI产生的异常 //IllegalArgumentException newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); if (newExc ==NULL) { printf("exception\n"); return; } //把异常抛给java层,让java可以捕获 (*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild "); } printf("exception\n"); } /* * JNI 局部静态变量进行缓存 * static 关键字:声明的变量是一个静态变量,static关键字声明的变量,在c语言中,会存储在一个静态区中, * 存储在静态区中的变量只需要声明和初始化一次,以后再次使用的时候,就可以直接使用,不会再从新创建, * 使用范围:局部的静态变量只在定义它的方法内有效,其他方法无法引用。 */ JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_cached (JNIEnv *env, jobject jobj) { jclass cls = (*env)->GetObjectClass(env, jobj); static jfieldID fid; if (fid == NULL) { fid = (*env)->GetFieldID(env, cls, "mKey", "Ljava/lang/String;"); printf("GetFieldID\n"); } } /* * JNI 全局静态变量进行缓存 * 使用范围:在定义位置之后的所有方法都可以调用,之前的方法无法调用 */ static jfieldID fid_glb; JNIEXPORT void JNICALL Java_com_mei_test_jni_JniTest_cachedGlobal (JNIEnv *env, jobject jobj){ jclass jclz = (*env)->GetObjectClass(env, jobj); if (fid_glb == NULL) { fid_glb = (*env)->GetFieldID(env, jclz, "mKey", "Ljava/lang/String;"); printf("fid_glb init\n");// } } /* * JNI 缓存策略和弱引用联合使用带来的问题 * */ JNIEXPORT jstring JNICALL Java_com_mei_test_jni_JniTest_accessCacheNewString (JNIEnv *env, jobject jobj) { //定义一个静态的局部变量 static jclass cls_string = NULL;//当内存不足的时候,在方法调用结束之后,JVM就会释放所有的局部变量, //这个时候cls_string这个局部静态变量就会指向一个空的内存空间,即产生了野指针, //解决方式:去掉static关键字,如果非要使用static,就一定要做好异常处理 if (cls_string == NULL) { printf("alvin in Java_JniMain_AcessCache_newString out: \n"); //给局部静态变量赋一个局部引用 cls_string = (*env)->FindClass(env, "com/mei/test/jni/Refrence"); } //使用这个静态局部变量 jmethodID jmid = (*env)->GetMethodID(env, cls_string, "getRef", "(I)I"); jthrowable ex = (*env)->ExceptionOccurred(env); if (ex != NULL) { jclass newExc; // 让java 继续运行 (*env)->ExceptionDescribe(env);//输出关于这个异常的描述 (*env)->ExceptionClear(env); printf("C exceptions happend\n"); } printf("alvin out Java_JniMain_AcessCache_newString\n"); return NULL; } /* * Class: com_mei_test_jni_JniTest * Method: accessCF * Signature: ()V */ JNIEXPORT jstring JNICALL Java_com_mei_test_jni_JniTest_accessCF (JNIEnv *env, jobject jobj) { //Sleep(100); return Java_com_mei_test_jni_JniTest_accessCacheNewString(env, jobj); }
相关文章推荐
- JNI 学习笔记(三)-- JNI访问数组、引用、异常处理、缓存策略
- NDK-JNI语法-数组处理+全局引用+异常处理+缓存策略
- JNI学习笔记5——本地方法处理java数组/引用问题/缓存jfieldID/jmethodID
- JNI学习笔记:(1)开篇(2)本地代码访问Java代码 (3)本地方法取得Java属性/调用java方法 (4)本地代码创建Java对象(包括javaString) (5) 本地方法处理java数组
- NDK开发学习笔记(2):JNI访问Java中的方法
- Android NDK (学习笔记六) —— JNI交互间数组的处理
- Android NDK(学习笔记四)—— 在NDK开发中JNI打印Log信息
- Android NDK (学习笔记七) —— JNI的交互处理之Eclipse开发工具配置
- NDK开发笔记(二)---JNI的学习
- Android(java)学习笔记259:JNI之NDK开发步骤
- Android-NDK开发之基础--Android JNI实例代码(四)-- JNI中的异常处理实例代码
- JNI学习笔记:异常处理
- Android-NDK开发之基础--Android JNI实例代码(四)-- JNI中的异常处理实例代码
- Android-NDK开发之基础--Android JNI实例代码(四)-- JNI中的异常处理实例代码
- JNI/NDK开发指南(四)--访问数组(基本类型数组与对象数)
- NDK开发笔记(二)---JNI的学习
- NDK开发学习笔记—C/C++访问java成员
- NDK开发学习笔记(1):JNI开发步骤及遇到的问题详解
- NDK开发学习笔记—C代码返回中文乱码处理
- Effective C# 学习笔记(四十七)对异常进行strong guarantee 策略处理