NDK开发学习笔记(3):JNI访问数组、引用、异常处理、缓存策略

来源:互联网 发布:手动下载windows更新 编辑:程序博客网 时间:2024/05/17 20:34
/** 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);}
阅读全文
0 0
原创粉丝点击