JNI详解(二)

    xiaoxiao2022-06-30  59

    1、局部引用

    从java native接口函数中传到C/C++的JNIEnv指针、jclass、jobject都是局部引用。

    大多数JNI函数返回的也是局部引用,例如FindClass、GetStaticMethodID等函数。

    局部引用的使用期限仅限于当前原生方法体,一旦原生方法返回局部引用随即被自动释放(也可以用env->DeleteLocalRef()显式释放)所以绝对不能缓存(作为全局变量缓存)下来重用。

    虚拟机允许原生代码在一次被调用时创建的局部引用是有限的(最少16个)。如果局部引用不够用,那就要及时删除用过的局部引用,或者调用EnsureLocalCapacity请求分配更多的局部引用槽。

    2、全局引用

    有些场合下需要1中的局部引用在后续的调用中有效(例如C/C++异步回调java)。这时就需要在局部引用的基础上创建全局引用。全局引用持续有效直至显式销毁。

    创建:env->NewGlobalRef

    销毁:env->DeleteGlobalRef

    3、弱全局引用

    弱全局引用同样可以在后续的调用中有效。

    2中的全局引用会阻止虚拟机垃圾回收机制对其回收,但是弱全局引用则有被回收的风险。

    创建:env->NewWakeGlobalRef

    检测有效性:env->IsSameObject(_myWakeGlobalRef,NULL) == JNI_FALSE ? 有效 : 无效

    销毁:env->DeleteWakeGlobalRef

    4、跨线程使用JNIEnv指针

    在java线程thread1里调用了native方法native_func_1,在native_func_1创建了全局引用global_ref_1

    在java线程thread2里调用了native方法native_func_2,在native_func_2里面要借助JNIEnv指针使用global_ref_1,例如env->GetObjectClass(global_ref_1)。

    虽然global_ref_1是全局引用,但在native_func_2里面直接借助JNIEnv指针使用global_ref_1时仍然会报错(注意,如果native_func_1和native_func_2都是在同一个线程里被调用,则在native_func_2里面直接借助JNIEnv指针使用global_ref_1不会报错)!

    解决方法是在native_func_1里创建全局引用global_ref_1的同时保存虚拟机状态,在native_func_2里面使用global_ref_1前恢复虚拟机状态。

    定义全局变量:

    jobject global_ref_1; JavaVM * java_vm;

    在native_func_1里创建全局引用global_ref_1的同时保存虚拟机状态:

    env->GetJavaVM(&java_vm); global_ref_1= env->NewGlobalRef(local_ref_1);

    在native_func_2里面使用global_ref_1前恢复虚拟机状态:

    java_vm->AttachCurrentThread(&env, NULL);

    env->GetObjectClass(global_ref_1);

    转载请注明原文地址: https://ju.6miu.com/read-1125810.html

    最新回复(0)