zoukankan      html  css  js  c++  java
  • Android jni/ndk编程四:jni引用类型

    一.JNI引用类型

    JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面我们将逐一探讨。

    local references

    大部分JNI 函数都会创建LocalRef,如NewObject创建一个实例,并返回一个指向该实例的LocalRef。LocalRef只在本线程的 native method中有效. 一但native method返回,LocalRef 将被释放。这意味着我们不能缓存LocalRef来提高效率,因为native方法一旦返回,LocalRef将被释放,缓存起来也没有用。 
    我们已经知道了大部分JNI函数都会创建LocalRef,比如NewObject,FindClass等,与创建相对应的,我们可以有两种方式让LocalRef 无效:

    1. native method返回,JavaVM自动释放LocalRef;
    2. 用DeleteLocalRef 主动释放。 
      DeleteLocalRef的定义如下:
        void        (*DeleteLocalRef)(JNIEnv*, jobject);

    DeleteLocalRef 主动释放LocalRef是有意义的,如果我们内存特别紧张,而一个本地的方法有很多很耗内存的LocalRef,这个时候,在本地方法中及时释放这些LocalRef可以缓解内存压力。 
    LocalRef只在创建该对象的线程中有效,因此我们无法在其他线程中使用共享LocalRef.

    Global References

    Global引用类似于全局变量,我们可以在多个native方法中使用,也可以在多个线程中使用。此外,Golbal引用会阻止GC回收。但是,与c总的全局变量不同的是,Golbal引用必须通过特定的函数手动创建和释放。以下是相关函数的定义:

        jobject     (*NewGlobalRef)(JNIEnv*, jobject);
        void        (*DeleteGlobalRef)(JNIEnv*, jobject);

    使用举例:

    //1.首先定义一个静态变量存储Global引用
    static jclass stringClass = NULL;
    //2.获得Local 引用
    jclass localRefCls = (*env)->FindClass(env,
    "java/lang/String");
    if (localRefCls == NULL) {
    return NULL; /* exception thrown */
    }
    //3.使用那个local引用创建全局引用
    stringClass = (*env)->NewGlobalRef(env, localRefCls);
    //4.及时释放Local引用
    (*env)->DeleteLocalRef(env, localRefCls);

    以上是常见的、简单的创建Global引用的代码流程,使用完以后,记得把它释放掉,不然后内存泄漏了,因为Global引用是阻止GC的。

    Weak Global References

    所谓弱全局引用就是全局引用的另一个版本,既然它是全局引用,那么它就具备了在多个线程中共享的能力,以及我们可以在单个线程的不同函数中都可以使用它。之所以说它弱是因为它无法阻止GC。前面我们说Global引用很强势,它只能手动释放,JVM虚拟机不能自动GC它,但是Weak Global就会被垃圾回收器回收,这就是它若的原因。 
    Weak Global Ref用 NewGlobalWeakRef于DeleteGlobalWeakRef进行创建和删除,多个本地方法调用过程中和多线程上下文中使用的特性与 GlobalRef相同。这两个函数在jni.h中的定义如下:

        jweak       (*NewWeakGlobalRef)(JNIEnv*, jobject);
        void        (*DeleteWeakGlobalRef)(JNIEnv*, jweak);

    我们看到这里又出现了一个新的类型:jweak,它其实就是jobject,只是名字不容而已:

    typedef jobject         jweak;

    用法举例:

    static jclass string= NULL;
    if (string == NULL) {
        jclass local_string =
        (*env)->FindClass(env, "java/lang/String");
        if (myCls2Local == NULL) {
            return; /* can’t find class */
        }
        string = NewWeakGlobalRef(env, local_string );
        if (myCls2 == NULL) {
            return; /* out of memory */
        }
    }

    由于Weak Global引用可能被垃圾回收器回收,所以我们在使用它之前一定要判断它是否为空。如果空的话需要重新创建它,不为空就继续使用。

    二.Comparing Reference

    既然我们可以有多个引用,它可能是全局引用,弱全局引用或局部引用,我们怎么判断它是不是同一个引用呢?不用急,JNI已经为我们提供好了函数,我们可以直接用,其定义如下:

    jboolean    (*IsSameObject)(JNIEnv*, jobject, jobject);

    如果相通,返回JNI_TRUE, 否则返回JNI_FALSE。

    三.引用管理

    引用管理是为了较少内存使用,提高代码效率。JNI支持的三种引用各有各得用途,绝不能滥用。笔者水平有限,就不多废话了,这里主要讲一下Local引用的管理。 
    JNI提供了一组管理Local引用的函数:

        jint        (*PushLocalFrame)(JNIEnv*, jint);
        jobject     (*PopLocalFrame)(JNIEnv*, jobject);

    在进入本地方法时,调用一次 
    PushLocalFrame,并在本地方法结束时调用 PopLocalFrame. 此对方法执行效率非常高,建议使用这对方法。 
    一定保证该上下文出口只有一个,或每个return语句都做严格检查是否调用了PopLocalFrame。因为如果忘记调用PopLocalFrame 可能会使JVM崩溃。 
    用法举例:

    jobject hello(JNIEnv *env, jobject obj)
    {
    jobject result;
    //进入函数后push
    if ((*env)->PushLocalFrame(env, 10) < 0) {
    /* frame not pushed, no PopLocalFrame needed */
    return NULL;
    }
    ...
    result = ...;
    if (...) {
    //认真检查每一个函数的出口,绝不能忘记PopLocalFrame
    result = (*env)->PopLocalFrame(env, result);
    return result;
    }
    ...
    //正常返回前pop一下
    result = (*env)->PopLocalFrame(env, result);
    return result;
    }
  • 相关阅读:
    数列分段
    2020-01-21 数组 最大子序和
    2020-01-21 数组
    补 2020-01-20 数组 删除排序数组中的重复项
    补2020-01-19 数组 两数之和
    2020-01-18 刷题 螺旋矩阵 II
    2020-01-16 刷题 长度最小的子数组
    2020-01-15 刷题 移除元素
    2020-01-14 QT学习记录
    2020-01-14 数组刷题-1
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/6895484.html
Copyright © 2011-2022 走看看