文档章节

传智播客JNI第七讲 – JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式

shzwork
 shzwork
发布于 06/26 21:11
字数 1543
阅读 10
收藏 0

 讲解JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式,并编写两种缓存方式的示例代码。

1.从Java虚拟机创建的对象传到本地C/C++代码时会产生引用,根据Java的垃圾回收机制,只要有引用存在就不会出发该引用指向的Java对象的垃圾回收。

2.这些引用在JNI中分为三种:
  全局引用:Global Reference
  局部引用:Local Reference
  若全局引用:Weak Global Reference since JDK1.2

3.局部引用
  1)最常见的引用类型,基本上通过JNI返回来的引用都是局部引用。例如使用NewObject就会返回创建出来的实例的局部引用,局部引用只在该native函数中有效,所有在该函数中产生的局部引用,都会在函数返回的时候自动释放,也可以使用DeleteLocalRef函数手动释放该引用。
  2)想一想既然局部引用能够在函数返回时自动释放,为什么还需要DeleteLocalRef函数呢?
  3)实际上,局部引用存在,就会防止其指向的对象被垃圾回收,尤其是当一个局部引用指向一个很庞大的对象,或是在一个循环中生成了局部引用,最好的做法就是在使用完该对象后,或在循环尾部把这个引用释放掉,以确保在垃圾回收器被处罚的时候被回收。
  4)在局部引用的有效期中,可以传递到别的本地函数中,要强调的是他的有效期仍然只在一次的Java本地函数调用中,所以千万不能用C++全局变量保存它或者把它定义为C++静态局部变量。

4.全局引用
  1)全局引用可以跨越当前线程,在多个native函数中有效,不过需要编程人员手动来释放该引用,全局引用存在期间会防止在Java的垃圾回收。
  2)与局部引用不同,全局引用的创建不是由JNI自动创建的,全局引用时需要调用NewGlobalRef函数,而释放它需要使用ReleaseGlobalRef函数。

5.弱全局引用
  1)Java1.2新出来的功能,与全局引用相似,创建跟删除都需要由编程人员来进行。这种引用与全局引用一样可以再多个本地代码有效,也跨越多线程有效,不一样的是,这种引用将不会阻止垃圾回收器回收这个引用所指向的对象。
  2)使用NewWeakGlobalRef跟ReleaseWeakGlobalRef来产生和解除引用。

6.关于引用的一些函数
  jobject NewGlobalRef(jobject obj);
  jobject NewLocalRef(jobject obj);
  jobject NewWeakGlobalRef(jobject obj);
  void DeleteGlobalRef(jobject obj);
  void DeleteLocalRef(jobject obj);
  void DeleteWeakGlobalRef(jobject obj);
  jboolean IsSameObject(jobject obj1, jobject obj2); // 这个函数对于弱全局引用还有一个特别的功能,把NULL传入要比较的对象中,就能够判断弱全局引用所指向的Java对象是否被回收。

7.缓存jfieldID,jmethodID
  1)取得jieldID跟jmethodID的时候会通过该属性、方法名称加上签名来查询相应的jfieldID,jmethodID。这种查询相对来说开销较大,我们可以将这些FieldID,MethodID缓存起来,这样只需要查询一次,以后就使用缓存起来的FieldID,MethodID。
  2)介绍两种缓存方式
   1.在用的时候缓存 
   2.在Java类初始化时缓存

  11)在第一次使用的时候缓存
     在native code中使用static局部变量来保存已经查询过的id,这样就不会再每次的函数调用时查询,而只要第一次查询成功后就保存起来了。
     不过在这种情况下就不得不考虑多线程同时呼叫此函数时可能会招致同时查询的危机,不过这种情况是无害的,因为查询同一个属性,方法的ID通常返回的是一样的值。
     JNIEXPORT void JNICALL Java_Test_native(JNIEnv* env, jobject obj){
 static jfieldID fieldID_string = NULL;
 jclass clazz = env->GEtObjectClass(obj);
 if(fieldID_string == NULL){
    fieldID_string = env->GetFieldID(clazz, "string", "Ljava/lang/String;");
 }
 // other code...

       }
 
     22)在Java类初始化的时候缓存
        更好的一个方式就是在任何native函数调用前把id全部存起来。
 我们可以让Java在第一次加载这个类的时候首先调用本地代码初始化所有的jfieldID,jmethodID,这样的话,就可以省去多次的确定id是否存在的语句,当然,这些jfieldID,jmethodID是定义在C/C++的全局。
 使用这种方式的好处,当Java类卸载或是重新加载的时候,也会重新呼叫该本地代码来重新计算IDs。

 

 

 

课程最后总结
在这一课中,我们学习了:
1.最简单的Java调用C/C++函数的方法
2.取得方法、属性的ID,学会了取得/设置属性,还有Java函数的调用。
3.Java/c++之间的字符串的转换问题。
4.在C/C++下如何操作Java数组。
5.三种引用方式
6.如何缓存属性和方法的ID

使用JNI的两个弊端
1.使用了JNI,那么这个应用就不能跨平台了,如果需要移植到别的平台上,那么native代码就需要重新编写。
2.Java是强类型的语言,而C/C++不是,你必须写JNI时更小心。
3.尽量少使用本地代码。

其它
1.异常处理
2.C/C++如何启动JVM
3.JNI跟多线程  
  介绍两本书作为参考:
  1)The Java Native Interface Programmer's Guide and Specification
  2))JNI++ User Guide

 

本文转载自:https://www.xuebuyuan.com/1475207.html

shzwork
粉丝 11
博文 587
码字总数 10198
作品 0
厦门
私信 提问
NDK开发中这些基本知识你都懂吗

JNIEnv 定义: 相当于一个jni上下文对象。 作用: 通过JNIEnv的指针能够对Java端的代码进行操作: a.创建Java对象. jstring str = (env).NewStringUTF("终端研发部"); jclass jclazz = (env)...

codeGoogle
2017/09/21
0
0
深入了解android平台的jni---本地多线程调用java代码

一、jni调用java对象 JNI提供的功能之一是在本地代码中使用Java对象。包括:创建一个java类对象和通过函数传递一个java对象。创建一个java类对象,首先需要得到得到使用FindClass/GetObject...

mfcai
2013/07/17
0
0
Android NDK对象的引用-全局引用,局部引用,弱引用

百度了一下,google了一下,关于NDK引用的介绍无10篇中就有9.9篇是相同的,对于这种问题,我只能呜呼哀哉了!! 局部引用(函数内部对象类型变量):在C或C++中,局部变量表示只运行范围局限...

IamOkay
2015/01/12
0
0
Android JNI开发系列(十二) JNI局部引用、全局引用和弱全局引用

JNI 局部引用、全局引用和弱全局引用 在JNI规范中定义了三种引用:局部引用(Local Reference)、全局引用(Global Reference)、弱全局引用(Weak Global Reference)。区别如下: 局部引用...

蔡小鹏
2018/10/18
0
0
JAVA之JNI小结

JNI 是 Java Native Interface 的缩写。 Java™ 本机接口(Java Native Interface,JNI)是一个标准的 Java API,它支持将 Java 代码与使用其他编程语言编写的代码相集成。如果您希望利用已有...

城固如春
2016/10/25
9
0

没有更多内容

加载失败,请刷新页面

加载更多

抽象同步队列AQS——AbstractQueuedSynchronizer锁详解

AQS——锁的底层支持 谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)! 类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资...

须臾之余
今天
3
0
springboot配置百度UEditor 富文本详解

富文本简介 UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码... 准备工作 ueditor需要单独文...

wotrd
昨天
4
0
mysql 5.7之my.cnf配置大全

[client]port = 3306socket = /tmp/mysql.sock[mysqld]###############################基础设置######################################Mysql服务的唯一编号 每个mysql服务...

Online_Reus
昨天
3
0
MAVEN打包时引入外部链接的包

1.项目引入了ORACLE的jar包,MAVEN配置如下 2.打jar包的时候需要指定下main入口函数mainClass <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> ......

Cobbage
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部