JNI - 缓存、 三大引用

在JNI中有很多方法会用到ID, 比如:getObjectField( jobject , fid) 获取java的字段, CallVoidMethod( jobject , mid ) 调用java的方法。可是在获取字段ID 和方法的ID时需要字段/方法名 和 描述 进行检索,这个过程相对比较耗时。如果还有频繁调用的情况,会大大降低方法的效率。此时我们需要使用缓存策略减少这个过程的消耗。

缓存策略根据缓存时机不同分为两种。一种:使用时缓存。第二种:初始化缓存。

使用时缓存

在调用方法时,将id写为静态变量,多次调用多线程调用id不用重新检索。但是在类被unload时会失效,在使用时要判空处理。下面代码缺少  env -> ReleaseStringUTFChars(Jstr,str);(局部变量方法使用完之后会自动回收,但会阻止它所引用的对象被回收。)

在java中调用

for( int i = 0 ; i < 100; i++){

          testCache();

}

结果输出:

初始化缓存

在静态代码块中加载库后直接调用初始化方法,Id变为全局变量,由于类被unload 和 reload时id会被从新计算无需担心。

结果输出 In C "哈哈哈啊"

局部引用

局部引用有JNI函数创建出来 getObject~  find~  new~ 这些创建出来的局部引用只能在本方法返回前有效。不可将局部引用缓存到静态变量中或存储到全局变量中,如:static jsclass clazz; 方法使用完后会被释放,下次进入方法时class已经是一个失效的引用,会引起程序崩溃。

代码创建大量局部引用时会造成引用表溢出,手动释放 env->DeleteLocalRef( obj )

for (int i = 0; i<len; i++){

       jobject obj = env ->newObject(....)

       env->DeleteLocalRef( obj )

 }

当然管理局部引用最合适的方法时使用Push/PopLocalFrame()函数。

#define NUM ( 20 );

f (JNIEmv *env , ...){

       jobject result;

       if(  env->PushlocalFrame(env,NUM) < 0){

         return;

       }

      result  =  env ->newObj~();

      .......省略........

      env ->PopLocalFrame( NULL);

}

全局引用

全局引用可以跨线程,跨方法使用,与局部引用一样会阻止他引用的对象被GC回收。创建方法:NewGlobalRef( ).( 如果在JNI中使用多线程需要重新获取env)。手动释放DeleteGlobalRef(glo);

弱引用 

与全局引用类似 NewGlobalWeakRef创建,跨线程,跨方法。特点:允许GC回收塔指向VM的对象。但在引用表中建立的映射不会回收,需要DeleteWeakGlobalRef( )。

 局部引用的内部实现 

一个对象从 JVM 传递给本地方法时,就把控制权移交了过去,JVM 会为每一个对象的传递创建 一条记录,一条记录就是一个本地代码中的引用和 JVM 中的对象的一个映射。记录中的对象不 会被 GC 回收。所有传递到本地代码中的对象和从 JNI 函数返回的对象都被自动地添加到映射表 中。当本地方法返回时,VM 会删除这些映射,允许 GC 回收记录中的数据。图 11.5 演示了局 部引用记录是怎么样被创建和删除的。一个 JVM 窗口对应一个本地方法,窗口里面包含了一个 指向局部引用映射表的指针。方法 D.f 调用本地方法 C.g。C.g 通过 C 函数 Java_C_g 来实现。 在进入到 Java_C_g 之前,虚拟机会创建一个局部引用映射表,当 Java_C_g 返回时,VM 会删 掉这个局部引用映射表。

为了在Linux环境下使用GmSSL的JNI接口,需要按照以下步骤进行操作: 1. 首先,在Linux系统上编译和安装GmSSL。可以从gmssl.git仓库中获取源代码,并执行make命令进行编译,然后使用make install命令将GmSSL安装到指定路径。比如,可以使用以下命令指定安装路径为`/usr/local/gmssl`: ``` make make install PREFIX=/usr/local/gmssl ``` 2. 编译成功后,可以在安装路径下找到生成的gmssl目录。接下来,需要将可执行文件gmssl复制到gmssl/bin目录,并生成JNI所需的动态链接库。具体的操作可以参考以下步骤: ``` cp gmssl /usr/local/gmssl/bin cd /usr/local/gmssl ldconfig # 更新动态链接库的缓存 ``` 3. 在使用JNI接口时,可以在应用程序中引入GmSSL的头文件,并调用相关的函数。例如,在GmSSL.c中可以实现描述中的简易JNI接口,同时也可以进行简单封装,方便直接调用sm2、sm3、sm4等算法。 总结起来,要在Linux环境下使用GmSSL的JNI接口,需要先编译和安装GmSSL,然后将可执行文件复制到指定目录,并生成JNI所需的动态链接库。最后,在应用程序中引入头文件并调用相关函数即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [GmSSL win10编译安装](https://blog.csdn.net/liuxing9345/article/details/110742166)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [java版sm4源码-gmssl-java-sdk:gmssl-java-sdk](https://download.csdn.net/download/weixin_38530995/19393365)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值