JNI详解(二)

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);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值