jni如何判断两个jobject是否为同一个java对象

jni开发时有时候需要将java对象缓存到native层,方便native层通过jni的反射方法进行回调操作。通常我们会将回调接口callback在native层存放为global reference全局引用,熟悉jni开发的都知道,jni传入到native 层的jobject生命周期仅仅是函数的生命周期,当jni函数返回后对应的jobject对象就会失效,不能再操作,所以就必须申请为global reference。

NewGlobalRef 将变量申请为全局引用,此时java虚拟机会保留jobject所指向的对象防止被垃圾回收器回收。 DeleteGlobalRef 释放全局引用,允许java虚拟机回收该引用指向的java对象,对于不需要使用的global reference必须调用该方法,否则会引起java虚拟机内存泄漏。

既然global reference的实质是指向java对象,那么我们在将某个变量声明为global reference时如何判断该jobject是否已经是当前设置的global reference呢。经过一番查询,看到了一下方法

IsSameObject 如果两个jobject指向同一个java 对象那么返回true,否则返回false。

既然有方法了,接下来就是验证工作了。

Hello.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     Hello* Method:    native_setObjectToGlobalRef* Signature: (LHello/Book;)V*/
JNIEXPORT void JNICALL Java_Hello_native_1setObjectToGlobalRef(JNIEnv *, jclass, jobject);/** Class:     Hello* Method:    native_release* Signature: ()V*/
JNIEXPORT void JNICALL Java_Hello_native_1release(JNIEnv *, jclass);#ifdef __cplusplus
}
#endif
#endif

Hello.cpp

#ifdef __cplusplus
extern "C" {
#endif#include <cstdio>
#include "Hello.h"// 全局变量,用于存储全局引用的
jobject g_book_ref = NULL; /** Class:     Hello* Method:    native_setObjectToGlobalRef* Signature: (LHello/Book;)V*/
JNIEXPORT void JNICALL Java_Hello_native_1setObjectToGlobalRef(JNIEnv *env, jclass jclazz, jobject jbook) {// 如果输入参数为null,那么不需要继续操作if (NULL == jbook) {printf("native_setObjectToGlobalRef jbook is NUll and g_book_ref is NOT NULL. we need to delete reference of old g_book_ref\n");if (NULL != g_book_ref) {env->DeleteGlobalRef(g_book_ref);  // 删除老的全局引用g_book_ref = NULL;}return;}// 如果全局引用已经设置了,那么需要判断jni函数参数的jbook是否与当前的全局引用指向同一个java对象if (NULL != g_book_ref) {// 如果指向同一个对象,那么不需要再次为该jbook申请全局引用if (env->IsSameObject(g_book_ref, jbook)) {printf("native_setObjectToGlobalRef isSameObject: true, g_book_ref: %p, jbook: %p\n", g_book_ref, jbook);} else {// 如果指向不同对象,那么先释放老的全局引用,再为jbook申请全局引用printf("native_setObjectToGlobalRef isSameObject: false\n");printf("native_setObjectToGlobalRef g_book_ref and jbook is not same object. we need to delete reference of old g_book_ref\n");env->DeleteGlobalRef(g_book_ref);printf("native_setObjectToGlobalRef create global reference to g_book_ref\n");g_book_ref = env->NewGlobalRef(jbook);}} else {printf("native_setObjectToGlobalRef g_book_ref is NULL\n");printf("native_setObjectToGlobalRef create global reference to g_book_ref\n");g_book_ref = env->NewGlobalRef(jbook);}
}/** Class:     Hello* Method:    native_release* Signature: ()V*/
JNIEXPORT void JNICALL Java_Hello_native_1release(JNIEnv *env, jclass jclazz) {printf("native_release g_book_ref: %p\n", g_book_ref);if (NULL != g_book_ref) {env->DeleteGlobalRef(g_book_ref);g_book_ref = NULL;}
}#ifdef __cplusplus
}
#endif

Hello.java

public class Hello {static {try {String sysName = System.getProperty("os.name");if (sysName.contains("Linux")) {System.load(System.getProperty("user.dir") + "/libHello.so");} else if (sysName.contains("Drawin") || sysName.contains("Mac")) {System.load(System.getProperty("user.dir") + "/libHello.dylib");}} catch (java.lang.UnsatisfiedLinkError e) {e.printStackTrace();System.err.println("load so failed.");System.exit(1);}}static class Book {public String name;public Book() {}public Book(String name) {this.name = name;}}public native static void native_setObjectToGlobalRef(Book book);public native static void native_release();public static void main(String args[]) {Book b1 = new Book();Book b2 = new Book();System.out.println("set b1");native_setObjectToGlobalRef(b1);System.out.println("set b2");native_setObjectToGlobalRef(b2);System.out.println("##set b2");native_setObjectToGlobalRef(b2);System.out.println("##set null");native_setObjectToGlobalRef(null);native_release();}
}

makefile

UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
main:gcc -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/darwin" Hello.cpp -dynamiclib -o libHello.dylib
endififeq ($(UNAME_S),Linux)
main:gcc -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" Hello.cpp -shared -fPIC -o libHello.so
endif

运行命令

$ make

$ javac Hello.java

运行程序

$ java -Djava.library.path=".:${JAVA_HOME}" Hello

输出结果

set b1
native_setObjectToGlobalRef g_book_ref is NULL
native_setObjectToGlobalRef create global reference to g_book_ref
set b2
native_setObjectToGlobalRef isSameObject: false
native_setObjectToGlobalRef g_book_ref and jbook is not same object. we need to delete reference of old g_book_ref
native_setObjectToGlobalRef create global reference to g_book_ref
##set b2
native_setObjectToGlobalRef isSameObject: true, g_book_ref: 0x7fb16ae08e90, jbook: 0x70000ce4a900
##set null
native_setObjectToGlobalRef jbook is NUll and g_book_ref is NOT NULL. we need to delete reference of old g_book_ref
native_release g_book_ref: 0x0

1. set b1时

因为是首次设置,此时native的g_book_ref还是null,没有被指向java对象,所以需要用全局引用为jbook保存java对象引用;

2. set b2时

isSameObject返回false,证明g_book_ref和jbook指向的对象不一样(此时jbook指向b2,而g_book_ref指向步骤1设置的b1),所以需要先删除老的b1全局引用再为b2申请全局引用;

3. 再次设置b2时

isSameObject返回true,证明g_book_ref和jbook指向的对象一样(此时jbook和g_book_ref都指向b2,注意两者的native地址不一样),为了节省操作,所以不需要在为jbook申请全局引用;

4. 设置为null

因为jbook为null,所以需要释放全局引用g_book_ref。

5. native释放

在Book native释放时因为步骤4已经提前释放了全局引用,所以不需要再释放了。

jni如何判断两个jobject是否为同一个java对象相关推荐

  1. DB2数据库 SQL语句判断两个日期 是否属于同一个季度

    根据字段dsdate选择月份,以下语句可以判断一个月份的季度, SQL语句为: CASE WHEN SUBSTR(dsdate,6,2) BETWEEN 1 AND 3 THEN 1WHEN SUBS ...

  2. ping——判断两个设备是否在同一个局域网下

    有时需要判断两个设备(有线/无线)是否在同一个局域网下面怎么操作呢? 一.ping简介 二.windows下 三.Linux下 四.注意事项 一.ping简介 ping 程序是对两台主机之间连通性进行 ...

  3. 如何判断两个IP地址是不是同一个网段(超实用)

    IP地址 IP地址被用来给Internet上的电脑一个编号.大家日常见到的情况是每台联网的PC上都需要有IP地址,才能正常通信.我们可以把"个人电脑"比作"一台电话&qu ...

  4. c++ 实现计算立方体面积体积 并 判断两个立方体是否相等 (类和对象学习)

    1.设计一个类 2.在私有权限内写立方体的属性 3.在公共权限内对立方体的属性进行可读可写操作 4.在类外定义一个bool类型的全局函数判断两个立方体是否相等 判断标准为:长宽高分别相等 code / ...

  5. 如何判断两个jq对象是同一个对象

    如果说要判断是否同一对象,当然是用 === 来判断,但实际上两个不同的 jQuery 对象可能是对同一个/组 DOM 对象的封装,这个时候可以用 is 来判断,比如 var a = $(". ...

  6. 判断两个单链表是否相交--java实现

    题目描述:单链表可能有环,也可能无环.给定两个单链表的头节点 head1 和 head2, 这两个链表可能相交,也可能不相交.请实现一个函数,如果两个链表相交,请返回相交 的第一个节点;如果不相交,返 ...

  7. 判断两棵二叉树是否相等(Java实现)

    判断树是否相等,就是判断树中的每一个节点是否相等,根节点和根节点做比较,根节点的左子节点和左子节点作比较,右子节点和右子节点作比较,直到没有节点比较为止,中间只要一个节点不相等,就返回false,只有 ...

  8. Java中判断两个日期是否在同一个月

    /*** 判断是否在同一个月** @return false:不在同一个月内,true在同一个月内*/public boolean isMonth(Date date1, Date date2) {C ...

  9. android 判断两个整数,【tips】判断两个整数是否是同一个数量级

    iOS8沙盒路径的变化 iOS8中的的沙盒路径发生了变化 之前是这样的路径,通过NSHomedictionary()获取的家路径 /Users/wupeng/Library/Application S ...

  10. java 转xml 变成两根下划线_XStream将java对象转换为xml时,对象字段中的下划线“_”,转换后变成了两个...

    使用XStream将java对象转换为xml时,需要对其中的一个字段加上CDATA,于是我自定义了一个XStream,主要代码如下:publicstaticXStreamcreateXstream() ...

最新文章

  1. 这可能是最简单易懂的机器学习入门
  2. iOS开发-简单工厂模式
  3. bug4 导入新工程时报 Target runtime com.genuitec.runtime.generic.jee60 is not defined
  4. matlab分类器设计,简单分类器的MATLAB实现.doc
  5. 软件调试学习笔记(三)—— 调试事件的处理
  6. 多个常见代码设计缺陷
  7. flutter webview浏览器及与js交互、打开第三方app
  8. 魔兽美服服务器维护,美服《魔兽世界》低人口密度服务器合并计划最新动态
  9. HDU1799 循环多少次?
  10. Swing 添加超链接 打开页面
  11. CodeMirror 多功能在线代码编辑器
  12. html中img显示旋转,css如何实现图片的旋转展示效果(代码示例)
  13. deepin上配置eclipse的hadoop开发环境
  14. CrossApp推出移动应用开发神器 CrossApp Style
  15. 华盛顿大学计算机专业gpa,以未决定专业进入大学再转计算机专业可行吗?
  16. 手机刷入面具_小米手机机型怎么刷入脸谱Magisk模块详细教程
  17. MATLAB将数据写入obj文件
  18. Java中的七种设计原则
  19. gsoc 任务_gsoc 2020火箭聊天React式全屏作曲家
  20. linux 查找替换

热门文章

  1. 操作系统课设 Nachos 实验二:Nachos 的 Makefiles
  2. 中科大和东北大学计算机考研,我国39所985高校,一共被分为五个档次,复旦大学处于第二档...
  3. 导入es数据_有道精品课实时数据中台建设实践
  4. linux文件系统与sysfs,Linux设备模型与Sysfs文件系统.doc
  5. 简单的ideatomcat热加载
  6. selenium-绕过登录
  7. JQuery的Ajax标准写法
  8. 使用DIME协议上传文件
  9. xtrabackup备份原理
  10. css之px自动转rem—“懒人”必备