栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JNI对Java对象的引用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JNI对Java对象的引用

参考文献:

JNI学习笔记——局部和全局引用

        JNI将Java层的类实例、数组类型暴露为不透明的引用,native层的代码会通过JNI提供的函数来访问这个不透明的引用。JNI中有着不同种类的引用,分别为局部引用、全局引用和弱全局应用。

        JNI对Java层实例的局部引用能够被自动释放,全局引用和弱全局引用在程序员主动释放之前都是有效的。JNI的局部引用和全局引用能够使Java中对应的实例不会被JVM的垃圾回收机制所回收,但是弱全局引用允许其对应的实例被回收。

局部引用

        JNI层要获取Java实例的引用,就是获取Java实例对应的jclass类,获取到jclass的方法有多种方式。

        JNI中除了Java基本类型的数组、String、Class和Throwable之外,其余的Java对象在JNI中都用jobject表示。所以jclass类的一种方式就是从jobject获取,如下所示:

extern "C"
JNIEXPORT jboolean JNICALL
Java_android_set(
        JNIEnv *env, jobject thiz, jobject ref, jstring module_name) {
    ...
    jclass clazz = env->GetObjectClass(thiz);
    ...
}

        thiz对应Java中的一个实例对象,在JNI层用jobject表示,通过env的GetObjectClass方法将jobject转换为jclass。

        或者通过Java中的完整包名加类名来获取jclass,如下所示:

extern "C"
JNIEXPORT jobject JNICALL
Java_....getList(JNIEnv *env, jobject instance) {
  ....
  jclass list_jclass = env->FindClass("java/util/List");
  ....
}

        以上两种方式获取到的Java层类的引用list_jclass 和clazz都是局部引用,当程序离开这个程序块的时候,list_jclass 和clazz就不能再被使用了,因为他们已经被JVM释放掉了。

全局引用

        当JNI中同一个进程的多个线程需要对Java中的同一个类型的类进行重复操作时,就需要将该局部引用升级为全局引用,如下所示:

jstring  
MyNewString(JNIEnv *env, jchar *chars, jint len)  
{  
    static jclass stringClass = NULL;  
    ...  
    if (stringClass == NULL) {  
        jclass localRefCls =  
            (*env)->FindClass(env, "java/lang/String");  
        if (localRefCls == NULL) {  
            return NULL;   
        }  
          
        stringClass = (*env)->NewGlobalRef(env, localRefCls);  
          
        (*env)->DeleteLocalRef(env, localRefCls);  
         ...  
    }  
    ...  
}  

        以上表示使用NewGlobalRef方法将一个局部引用localRefCls转换为一个全局引用stringClass的方法,这个时候stringClass 这个引用即使在代码退出这个代码块之后也不会被释放,可以使用env的DeleteGlobalRef 方法来释放这个全局引用。

        需要注意的是这里使用env的DeleteLocalRef方法来主动释放一个JNI的局部引用,DeleteLocalRef方法需要使用的场景如下有:

1、创建大量 JNI 局部引用(在循环体或回调函数中),即使它们并不会被同时使用,因为 JVM 需要足够的空间去跟踪所有的 JNI 引用,所以可能会造成内存溢出或者栈溢出。

2、如果对一个大的 Java 对象创建了 JNI 局部引用,也必须在使用完后手动释放该引用,否则 GC 迟迟无法回收该 Java 对象也会引发内存泄漏。

弱全局引用

        

JNIEXPORT void JNICALL  
Java_mypkg_MyCls_f(JNIEnv *env, jobject self)  
{  
    static jclass myCls2 = NULL;  
    if (myCls2 == NULL) {  
        jclass myCls2Local =  
            (*env)->FindClass(env, "mypkg/MyCls2");  
        if (myCls2Local == NULL) {  
            return;   
        }  
        myCls2 = NewWeakGlobalRef(env, myCls2Local);  
        if (myCls2 == NULL) {  
            return;
        }  
    }  
    ... 
}  

        以上表示使用NewWeakGlobalRef将一个局部引用升级为弱全局引用的方法。弱全局引用和全局引用一样,可以跨越native的方法,以及跨线程使用。和全局引用不同的地方在于,弱全局引用不会阻止对基础对象的垃圾回收,所以使用弱全局引用之前需要检查该弱全局引用是否有效。使用DeleteWeakGlobalRef释放一个弱全局引用。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425283.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号