本文是《The Java Native Interface Programmer’s Guide and Specification》读书笔记


JNI支持将类实例和数组类型(如jobject,jclass,jstring,jarray)作为不透明的引用。本地代码不直接检查不透明指针的内容,而是通过使用JNI方法来得到一个指向数据结构的指针的不透明引用。也就是说JNI操作的内容都是引用,因此我们只需要知道在JNI中有哪些引用。JNI支持三种不透明的引用:本地引用、全局引用,弱全局引用。

 本地引用和全局引用有不同的生命周期,本地引用是自释放的,而全局和弱全局引用需要程序员主动释放掉,否则会一起存在于程序中。本地引用和全局引用的对象不会被垃圾回收器回收(也就是只要存在本地引用或全局引用,这个对象就被认为是活跃的),而弱全局引用允许引用对象被垃圾回收器回收。需要注意的是,引用并不是在所有的上下文中都是有效的,也就是引用是有生命周期的,比如,你不能在本地代码(JNI方法的实现代码)中使用完本地引用后,将这个引用通过return语句返回(本地引用在使用完后,已经结束了生命周期,系统中将不存在这个引用了)。

本地引用(Local References)

大部分的JNI方法(函数)都会创建本地引用,比如,通过JNI方法NewObject创建一个新的实例,并返回这个实例的引用。我们在本地方法里不能通过静态变量来保存一个本地引用。下面是一个错误的例子。

jstring
MyNewString(JNIEnv *env, jchar *chars, jint len)
{
//试图通过一个静态变量来保存本地引用
static jclass stringClass = NULL;
jmethodID cid;
....
//判断本地引用是否为空
if (stringClass == NULL) {
stringClass = (*env)->FindClass(env,
"java/lang/String");
if (stringClass == NULL) {
return NULL; /* exception thrown */
}
}
/* 这里就会发生错误,因为stringClass指向的对象可能不存在了*/
cid = (*env)->GetMethodID(env, stringClass ,
"<init>", "([C)V");
....
}
上面的代码中,试图通过一个静态变量来保存本地引用,这也许可以减小重复调用`FindClass`方法的开销,这个方法在第一次调用时不会出错,可以正常执行。但当第二次调用这个方法时,就会出错了。因为本地引用在这个本地方法执行完后就自动释放了,虽然stringClass保存了上一次执行的引用,但它指向的那个对象可能由于没有任何引用,被垃圾回收器回收了,所以在第二次执行时,试图去找到一个并不存在的对象,肯定是会出错的。并且本地引用只存在于创建时所在的线程,不能在其他线程中使用。因此不能通过试图将本地引用保存在全局变量中,以便在其他线程中使用。

全局引用(Global References)

我们可以通过全局引用来保存调用本地方法的某些结果,以便在下次调用时使用。同样的,全局引用可以在多个线程中使用(不局限于创建时所在的线程),并且在程序员主动释放前,都会一直有效。可以通过下面的代码来创建一个全局引用:
/* This code is OK */
jstring
MyNewString(JNIEnv *env, jchar *chars, jint len)
{
static jclass stringClass = NULL;
...
if (stringClass == NULL) {
jclass localRefCls =
(*env)->FindClass(env, "java/lang/String");
if (localRefCls == NULL) {
return NULL; /* exception thrown */
}
/* 用一个本地引用参数来创建一个全局引用 */
stringClass = (*env)->NewGlobalRef(env, localRefCls);
/* 释放掉本地引用 */
(*env)->DeleteLocalRef(env, localRefCls);
/* 判断全局引用是否创建成功 */
if (stringClass == NULL) {
return NULL; /* out of memory exception thrown */
}
}
...
}

弱全局引用(Weak Global References)

弱全局引用与全局引用类似,也可以在线程间共享和多次调用本地方法时共享。但也有区别,首先全局引用是通过JNI方法`NewGlobalRef`创建的,而弱全局引用是通过JNI方法`NewGlobalWeakRef`,并通过JNI方法`DeleteGlobalWeakRef`释放;其次弱全局引用并不会保证所引用的对象不会被垃圾回收器回收。因此我们在使用弱全局引用时,需要检查引用所反射的对象是否还存活。

杂谈

给定两个本地,全局或弱全局引用,我们可以通过JNI方法1isSameObject来判断这两个引用是不是指向同一个对象。返回JNI_TRUE,JNI_FALSE,NULL分别表示指向同一个对象,不是指向同一个对象,指向一个空对象。

Java里的引用类型

Java里一共有四种引用类型(摘录自以前的笔记,但不知道是从哪里看到的的):

  • 强引用,在代码中普遍存在,类似于Object object=new Object()这类的引用,只要强引用不存在,则GC永远不会回收掉引用的对象;
  • 软引用,用来描述一些有用但非必须的对象。对于软引用关联着的对象,在系统将在发生内存溢出时,将会把这些对象列入回收范围之中进行二次回收,如果这次还没有回收到足够的内存,才会抛出内存溢出异常。在JDK1.2后,提供了SofeReference来建立软引用;
  • 弱引用,也用来描述非必须对象,但强度比弱引用更弱一些,被弱引用关联的对象只能存活到下一次GC发生之前,当GC工作时,无论当时内存是否足够,都会被回收,可以用WeakReference来建立弱引用。
  • 虚引用,虚引用也叫幻影引用,这是最弱的一种引用,一个对象是否虚引用都不会对其生存时构成影响,也不能通过虚引用来取得一个对象实例。为一个对象设置虚引用的目的就是在这个对象被回收时收到一个通知,可以通过PhantomReference来建立虚引用。

Java Native Interface 四--JNI中引用类型的更多相关文章

  1. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  2. Java Native Interface 六JNI中的异常

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...

  3. Java Native Interface Specification(JNI)

    Java Native Interface Specification(JNI) 使用场景: 需要的功能,标准的java不能提供 有了一个用其他的语言写好的工具包,希望用java去访问它 当需要高性能 ...

  4. Java Native Interface 基于JNI的嵌入式手机软件开发实例

    1.通过JNI和c/c++的库组件.其他代码交互 2.java和c不能互通的原因时数据类型问题 Introduction https://docs.oracle.com/javase/8/docs/t ...

  5. Java Native Interface 五 JNI里的多线程与JNI方法的注册

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...

  6. Java Native Interface(JNI)

    JNI能让Java代码在Java虚拟机里调用其他编程语言(例如C.C++)写的应用或库,且不会影响任何Java虚拟机的实现. 什么时候用JNI? 1.应用程序所需的平台相关功能,标准的Java类库不支 ...

  7. 【详解】JNI (Java Native Interface) (二)

    案例二:传递参数给C代码,并从其获取结果 注:这里传递的参数是基本类型的参数,在C代码中有直接的映射类型. 此案例所有生成的所有文件如下: (1)编写案例二的Java代码,如下: 这里我们定义了一个n ...

  8. +Java中的native关键字浅析(Java+Native+Interface)++

    JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...

  9. Java Native Interface Specification Contents 翻译

    https://docs.oracle.com/en/java/javase/12/docs/specs/jni/index.html Google翻译 第1章:简介 本章介绍Java Native ...

随机推荐

  1. javascript中的自执行函数

    学习es6的时候遇到了自执行函数,感觉有必要写下来,一方面加深自己的记忆,另一方面还能分享给大家. 什么是自执行函数? 自执行函数就是为了不污染全局变量命名空间的一中匿名函数,相当于自己创建了一个作用 ...

  2. C++类继承关系视图的自动生成

    原创文章,转载请注明出处. 工欲善其事,必先利其器.阅读大型C++工程项目,如果有一些自动化的分析工具支持,学习的效率将大大提升.在前文中介绍了Source Insight在Linux下的安装方法,本 ...

  3. dubbo/dubbox 增加原生thrift及avro支持

    (facebook) thrift / (hadoop) avro / (google) probuf(grpc)是近几年来比较抢眼的高效序列化/rpc框架,dubbo框架虽然有thrift的支持,但 ...

  4. WIN10下安装HBASE教程

    工作需要,现在开始做大数据开发了,通过下面的配置步骤,你可以在win10系统中,部署出一套hadoop+hbase,便于单机测试调试开发. 准备资料: 1. hadoop-2.7.2: https:/ ...

  5. telent对端口检测状态分析

    telnet基于TCP/IP协议通信的,把远程的shell反弹回本地! yum install -y telnet apt-get  install telnet ###端口被封,有墙堵住 [root ...

  6. asp.net mvc 绑定客户端post过来的复杂JSON数据

    客户端代码如下: <input type="button" id="btnTest" value="测试" /><br / ...

  7. CephRGW 在多个RGW负载均衡场景下,RGW 大文件并发分片上传功能验证

    http://docs.ceph.com/docs/master/radosgw/s3/objectops/#initiate-multi-part-upload 根据分片上传的API描述,因为对同一 ...

  8. 【日常操作记录】Asp.Net Core 的一些基本操作或属性

    用于记录在项目中使用到的方法.属性.操作,持续更新中 静态文件的使用 在项目中静态文件的使用需要在Startup中的Configure方法中增加: //使用静态文件 app.UseStaticFile ...

  9. idea 如何隐藏/展示不想看到的文件

    隐藏:在 Ignore files and folders中添加想要过滤的文件或文件夹名称 展示隐藏文件: 在过滤列表中删除掉文件或者文件夹就好了

  10. rt3070 驱动异常问题

    新买的 Wi-Fi 网卡插在板子上,不能用.dmesg 查看,看到下面的内容. [ 9.501098] phy0 -> rt2x00lib_request_firmware: Error - F ...