【GiraKoo】Java Native Interface(JNI)的空间(引用)管理

这篇具有很好参考价值的文章主要介绍了【GiraKoo】Java Native Interface(JNI)的空间(引用)管理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java Native Interface(JNI)的空间(引用)管理

Java是通过垃圾回收机制回收内存,C/C++是通过malloc,free,new,delete手动管理空间。那么在JNI层,同时存在Java和C/C++的空间时,该如何进行空间的管理呢?本文参考Oracle的官方文档,对JNI层中空间的管理进行说明。明确哪些内容需要手动调用Delete,哪些不需要手动调用。

一、全局引用(Global References)

全局引用的生命周期(Lifetime),需要主动通过函数调用进行申请和释放。native函数执行完毕后,该空间可继续使用。

函数原型

// 创建全局引用
jobject NewGlobalRef(JNIEnv *env, jobject obj);  

// 删除全局引用
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);

二、局部引用(Local References)

局部引用的生命周期(Lifetime),与调用的native函数一致。当native函数return时,局部引用将会被自动释放。该局部引用占用的空间是JVM的资源。

由于native函数用于存放局部引用的空间是固定的。如果过度的创建局部引用,不加以控制,可能会出现空间不足,程序抛出Out Of Memory(OOM)异常的问题。如果该局部引用已经使用完毕,应尽量手动调用DeleteLocalRef,提前释放空间,避免OOM。

函数原型

// 创建全局引用
jobject NewLocalRef(JNIEnv *env, jobject obj);  

// 删除全局引用
void DeleteLocalRef(JNIEnv *env, jobject localRef);

// 主动设置可创建的局部引用的数量
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);

// 创建一个局部引用的帧,并指定可创建的局部引用的数量。
jint PushLocalFrame(JNIEnv *env, jint capacity);

// 释放当前局部引用的帧,释放全部本地引用。
// 可以通过参数result,将被PopLocalFrame释放的引用转移到上一层的局部引用帧中
jobject PopLocalFrame(JNIEnv *env, jobject result);

特殊说明

  1. 在JDK/JRE 1.1版本中,提供了DeleteLocalRef函数。
  2. 在JDK/JRE 1.2版本中,提供了EnsureLocalCapacityPushLocalFramePopLocalFrameNewLocalRef函数,支持更加复杂的局部引用生命周期能力。

三、弱全局引用(Weak Global Reference)

区别于全局引用(Global References),该引用并不会增加该引用的引用计数。

即持有弱全局引用,不会干预垃圾回收机制(GC)对于该内存的回收。适用于生命周期短的对象,持有生命周期长的引用。

全局引用可以通过jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); 函数,参数为被判定对象和NULL来判断对象是否存在。如果返回JNI_TRUE判定该弱引用指向的对象是否已经被释放。

使用弱全局引用时,可能会出现执行一半,引用被GC回收的情况。所以需要在使用弱全局引用之前,提供NewLocalRef或者NewGlobalRef,将弱引用转换为强引用。确保GC不会对该空间进行回收。

四、常见问题

1、在native函数中,直接return一个jstring或者其他jobject,是否会有内存泄漏问题?

如果直接return的对象是局部引用(Local Reference),则不会发生内存泄漏问题。
局部引用在native函数执行完毕后,会根据局部引用表(Local Reference Table)进行空间的释放。
当然,手动执行DeleteLocalRef函数进行提前释放,也不会产生问题。

2、什么情况下可能会出现内存泄漏?

1)创建的全局引用(Global Reference),未调用Delete函数进行回收。导致该对象引用计数无法归零。
2)两个对象互相持有对方的强引用。例如A持有B引用,B和C互相持有对方的引用。当A释放B引用时,GC发现C依然持有B的引用,则不会释放B。与此同时,GC也发现B持有C的引用,则不会释放C。导致B和C与其他引用脱离,形成孤岛。这块内存将无法使用,也无法被释放。

3、调用NewString和NewStringUTF时,是否需要释放?

NewStringNewStringUTF函数创建的空间属于局部引用(Local Reference)。可以等待native函数执行完毕后自动回收,也可以在使用完毕(后续不会再访问)后,直接进行Delete释放。

但是需要注意,如果通过GetStringCharsGetStringCritical或者GetStringUTFChars获取了jstring中的char* 空间,则需要使用对应的ReleaseStringCharsReleaseStringCritical或者ReleaseStringUTFChars释放该char* 空间。文章来源地址https://www.toymoban.com/news/detail-449138.html

参考文章

  • JNI Functions (oracle.com)

到了这里,关于【GiraKoo】Java Native Interface(JNI)的空间(引用)管理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Android】 频繁刷新 RecyclerView导致View 对象引用过多引起的Native 内存占用过大解决办法

    在 RecyclerView 中,如果频繁刷新 RecyclerView,可能会导致 Native 内存中有大量的 TextView 对象,从而导致内存占用过多的问题。以下是一些可能导致该问题的原因和解决方法: 使用 ViewHolder 在 RecyclerView 中,使用 ViewHolder 可以避免频繁创建和销毁 View 对象,从而减少内存占用。可

    2024年02月08日
    浏览(83)
  • Go语言入门记录:从基础到变量、函数、控制语句、包引用、interface、panic、go协程、Channel、sync下的waitGroup和Once等

    程序入口文件的包名必须是main,但主程序文件所在文件夹名称不必须是 main ,即我们下图 hello_world.go 在 main 中,所以感觉 package main 写顺理成章,但是如果我们把 main 目录名称改成随便的名字如 filename 也是可以运行的,所以迷思就在于写在文件开头的那个 package main 和 java

    2024年02月11日
    浏览(36)
  • Android Java代码与JNI交互 JNI访问Java类方法 (七)

    🔥 Android Studio 版本 🔥    🔥 创建包含JNI的类 JNIAccessMethod.java 🔥  🔥 Java方法对应Native层方法名称 🔥 🔥 配置动态库名称 🔥  🔥 生成可关联的库链接 🔥  为了让Java能够调用 access-method-lib 库中的函数,您需要使用 CMake 构建脚本中的 target_link_libraries() 命令来关联 

    2024年02月16日
    浏览(41)
  • Android Java代码与JNI交互 JNI方法Java类字段 (六)

    🔥 Android Studio 版本 🔥    🔥 Java 基础类型数据对应 Native层的字母 🔥  通过 jni 查找java某个类中相应字段对应的数据类型 , 需要使用到 jni 中的 GetFieldID() 函数 🔥 Java 引用类型数据对应 Native层字符串 🔥   🔥 创建 JNIAccessField 文件 🔥 🔥 配置动态库名称 🔥  🔥 生成

    2024年02月16日
    浏览(44)
  • Android Java代码与JNI交互 JNI访问Java构造方法(九)

    🔥 Android Studio 版本 🔥    🔥 创建包含JNI相关函数类 JNIConstructorClass.java 🔥  🔥 配置动态库名称 🔥   🔥 生成可关联的库链接 🔥  为了让Java能够调用 constructor-class-lib 库中的函数,您需要使用 CMake 构建脚本中的 target_link_libraries() 命令来关联constructor-class-lib 库  🔥

    2024年02月15日
    浏览(40)
  • Android Java代码与JNI交互 JNI子线程访问Java方法 (八)

    🔥 Android Studio 版本 🔥   🔥 创建包含JNI相关函数类 JNIInvokeMethod.java 🔥  🔥 配置动态库名称 🔥  🔥 生成可关联的库链接 🔥  为了让Java能够调用 invoke-method-lib 库中的函数,您需要使用 CMake 构建脚本中的 target_link_libraries() 命令来关联 invoke-method-lib 库  🔥 提供给N

    2024年02月16日
    浏览(49)
  • Android:JNI实战,理论详解、Java与Jni数据调用

    上一篇博文《Android:JNI实战,加载三方库、编译C/C++》讲解了如何搭建一个可以加载和链接第三方库、编译 C/C++ 文件的 Jni Demo App。 这篇博文在这个 Jni Demo App 的基础上,从实战出发详细讲解  Jni  开发语法。 接下来,先用一小节将 Jni 开发比较重要的理论知识点过一下,然

    2024年01月23日
    浏览(48)
  • C++心决之命名空间、重载函数和引用

    目录 1. C++(C++98) 2. 命名空间 2.1 命名空间定义 2.2 命名空间使用 3. C++输入输出 4. 缺省参数 4.1 缺省参数概念 4.2 缺省参数分类 5. 函数重载 5.1 函数重载概念 5.2 C++支持函数重载的原理--名字修饰(name Mangling) 6. 引用 6.1 引用概念 6.2 引用特性 6.3 常引用 6.4 使用场景 6.5 传值、

    2024年04月17日
    浏览(37)
  • C++:命名空间,缺省参数,函数重载,引用,内联函数

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C++》 本篇博客作为C++知识总结,我们来认识命名空间,缺省参数,函数重载,引用,内联函数。 那么在介绍命名空间时,我们先用C++的方式打印\\\"hello world\\\"。 其中,using namespace std; 就是一种命名空间的使用。 在

    2024年02月11日
    浏览(46)
  • C#中引用命名空间和using的用法

    **namespace:**创建命名空间 **using:**引用,使用:这里表示引用命名空间,第二个作用实例化对象时,对象执行完大括号内立刻释放空间。必须实现IDisposable接口的对象才能使用using释放资源。 C#中引用命名空间是指在编写代码时,使用using来引用一个或多个命名空间,

    2024年02月01日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包