首先来看一下C/C++中的引用

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

第一、局部引用:

最常见的引用类型,基本上通过JNI返回来的引用都是局部引用,例如使用NewObject就会返回创建出来的实例的局部引用,局部引用只在该native函数中有效,所有在该函数中产生的局部引用,都会在函数返回的时候自动释放,也可以使用DeleteLocalRef函数手动释放该引用

想一想既然局部引用能够在函数返回时自动释放,为什么还需要DeleteLocalRef函数呢

实际上局部引用存在,就会防止其指向的对象被垃圾回收,尤其是当一个局部引用指向一个很庞大的对象,或是在一个循环中生成了局部引用,最好的做法就是在使用完该对象后,活在该循环尾部把这个引用释放掉,以确保在垃圾回收器被触发的时候被回收

在局部引用的有效期中,可以传递到别的本地函数中,要强调的是他的有效期任然只在一次的Java本地函数调用中,所以千万不能用C++全局变量保存他或是把他定义为C++静态局部变量

第二、全局引用

全局引用可以跨越当前线程,在多个native函数中有效,不过需要编程人员手动来释放该引用,全局引用存在期间会防止在Java的垃圾回收器的回收

与局部引用不同,全局引用的创建不是由JNI自动创建的,全局引用是需要调用NewGlobalRef函数,而释放他需要使用ReleaseGlobalRef函数

弱全局引用

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

使用NewWeakGlobalRefReleaseWeakGlobalRef来产生和解除引用

关于引用的一个函数:

jobject NewGlobalRef(jobject obj);

jobject NewLocalRef(jobject obj);

jobject new WeakGlobalRef(jobject obj);

void DeleteGobalRef(jobject obj);

void DeleteLocalRef(jobject obj);

void DeleteWeakGlobalRef(jobject obj);

上述的六种方法很好理解的,这里就不做揭示了

jboolean IsSameObject(jobject obj1 , jobject obj2);

这个函数就是用来比较两个引用是否相等,但是对于弱全局引用还有一个特别的功能,如果把NULL传入要比较的对象中,就能够判断弱全局引用所指向的Java对象是否被回收

缓存jfieldID/jmethodID

取得jfieldID和jmethodID的时候会通过该属性/方法名称加上签名来查询相应的jfieldID/jmethodID.这种查询相对于来说开销大,我们可以将这些FieldID/MethodID缓存起来,这样就需要查询一次,以后就是用缓存起来的FieldID/MethodID了

下面介绍两种缓存方法是:

1.在用的时候缓存

在native code 中使用static 局部变量来保存已经查询过的id,这样就不会在每次的函数调用时查询,而只要第一次查询成功后就保存起来了

不过在这种情况下就不得不考虑多线程同时呼叫此函数时可能会招致同时查询的危机,不过这种情况是无害的,因为查询同一个属性/方法的ID通常返回的是一样的值

在static jfieldID fieldID_string = NULL;这段代码只执行一次

2.在Java类初始化时缓存

更好的一个方式就是在任何native函数调用前把id全部存起来

我们可以让Java在第一次加载这个类的时候首先调用本地代码初始化所有的jfieldID/jmethodID,这样的话就可以省去多次的确定id是否存在的语句,当然,这些jfieldID/jmethodID是定义在C/C++的全局

使用这种方式还有好处,当Java类卸载或是从新加载的时候,也会重新呼叫该本地代码来从新计算IDs

在Java中使用静态代码块中进行初始化

使用JNI中的两个弊端:

1.使用了JNI,那么这个Java Application将不能跨平台了,如果要移植到别的平台上,那么native代码就需要从新进行编写

2. Java是强类型语言,而C/C++不是,因此,你必须在写JNI的时候更加小心

介绍两本资料:

The Java Native Interface Programmer's Guide and Specification

JNI++ User Guide



关于JNI的学习到此结束!

Java中JNI的使用详解第六篇:C/C++中的引用类型和Id的缓存的更多相关文章

  1. Java中JNI的使用详解第三篇:JNIEnv类型中方法的使用

    转自: http://blog.csdn.net/jiangwei0910410003/article/details/17466369 上一篇说道JNIEnv中的方法的用法,这一篇我们就来通过例子来 ...

  2. Java中JNI的使用详解第五篇:C/C++中操作Java中的数组

    在Java中数组分为两种: 1.基本类型数组 2.对象类型(Object[])的数组(数组中存放的是指向Java对象中的引用) 一个能通用于两种不同类型数组的函数: GetArrayLength(ja ...

  3. Java中JNI的使用详解第四篇:C/C++中创建Java对象和String字符串对象及对字符串的操作方法

    首先来看一下C/C++中怎么创建Java对象:在JNIEnv中有两种方法是用来创建Java对象的: 第一种方法: jobject  NewObject(jclass clazz  , jmethodI ...

  4. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  5. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  6. Java中JNI的使用详解第一篇:HelloWorld

    转自: http://blog.csdn.net/jiangwei0910410003/article/details/17465085 今天开始研究JNI技术,首先还是老套路,输出一个HelloWo ...

  7. Java中JNI的使用详解第二篇:JNIEnv类型和jobject类型的解释

    上一篇说的是一个简单的应用,说明JNI是怎么工作的,这一篇主要来说一下,那个本地方法sayHello的参数的说明,以及其中方法的使用 首先来看一下C++中的sayHello方法的实现: JNIEXPO ...

  8. Java网络编程与NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,目前在蚂蚁财富负责后端开发工作,专注于 JAVA 后端技术栈,同时也懂点投资理财,坚持学习和写作,用大厂程序员的视角解读技术与互联网,我的世界里不 ...

  9. Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型

    本文转自:http://www.sohu.com/a/203838233_827544 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 ht ...

随机推荐

  1. Delphi如何获取一个字符串再另一个字符串中最后一次出现的位置

    uses StrUtils;   function ReversePos(SubStr, S: String): Integer; var   i : Integer; begin   i := Po ...

  2. Docker 部署 nginx 前端项目

    docker pull nginx docker run -itd -p 82:80 -v /opt/soft/nginx/conf/nginx.conf:/etc/nginx/nginx.conf ...

  3. synchronized(this) 与 synchronized(class) 理解

    1.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...

  4. 创建TCP服务器和TCP客户端

    import sockethost='127.0.0.1'port=8080web=socket.socket()web.bind((host,port))web.listen(5)# 设置最多连接数 ...

  5. YII 中加入短信接口的函数

    public function smsto($telphone,$message) { //短信接口用户名 $uid,如果没有或不能发送请与客服联系 $uid = 'zyd'; //短信接口密码 $p ...

  6. Hdu-4757 Tree(可持久化字典树+lca)

    题目链接:点这 我的github地址:点这     Problem Description   Zero and One are good friends who always have fun wi ...

  7. 2.4 webpack + gulp 构建完整前端工作流

    在前面的两个小节中已经完整的讲了 webpack 和 gulp 相关的内容,本小节中将会结合二者构建一个完整的前端工作流,内容目录为: 前端工程结构和目标 前端工程目录结构 gulp clean gu ...

  8. build protobuf to a static library

    use ar cd src ar -cvq libprotobuf.a *.o

  9. 如何发现 Redis 热点 Key ,解决方案有哪些?

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 来源:http://t.cn/EAEu4to 一.热点问题产生原因 热点问题产生的原因大致有以下两种: 1.1 用户消费的数 ...

  10. C# WinForm 第一个项目控件使用心得

    1.控件心得 1.1 基础控件 panel 作用:布局 难点:重绘边框改变颜色 重绘panel里如果有fill填充控件 panle的padding要改个值 private void pnlPaintB ...