【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);
特殊说明
- 在JDK/JRE 1.1版本中,提供了
DeleteLocalRef函数。 - 在JDK/JRE 1.2版本中,提供了
EnsureLocalCapacity,PushLocalFrame,PopLocalFrame,NewLocalRef函数,支持更加复杂的局部引用生命周期能力。
三、弱全局引用(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时,是否需要释放?
NewString和NewStringUTF函数创建的空间属于局部引用(Local Reference)。可以等待native函数执行完毕后自动回收,也可以在使用完毕(后续不会再访问)后,直接进行Delete释放。
但是需要注意,如果通过GetStringChars,GetStringCritical或者GetStringUTFChars获取了jstring中的char* 空间,则需要使用对应的ReleaseStringChars,ReleaseStringCritical或者ReleaseStringUTFChars释放该char* 空间。
参考文章
【GiraKoo】Java Native Interface(JNI)的空间(引用)管理的更多相关文章
- JAVA Native Interface (JNI)
1. Introduction At times, it is necessary to use native (non-Java) codes (e.g., C/C++) to overcome ...
- java native interface JNI 调用Java方法
在上一篇文章中介绍了JNI.以及java调用JNI.这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你能够创建Java对象,get.set 静态(static)和 实例(instanc ...
- Java Native Interface 基于JNI的嵌入式手机软件开发实例
1.通过JNI和c/c++的库组件.其他代码交互 2.java和c不能互通的原因时数据类型问题 Introduction https://docs.oracle.com/javase/8/docs/t ...
- +Java中的native关键字浅析(Java+Native+Interface)++
JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...
- Java Native Interface 五 JNI里的多线程与JNI方法的注册
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...
- Java Native Interface 四--JNI中引用类型
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI支持将类实例和数组类型(如jobjec ...
- Java Native Interface 二 JNI中对Java基本类型和引用类型的处理
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...
- 【详解】JNI (Java Native Interface) (四)
案例四:回调实例方法与静态方法 描述:此案例将通过Java调用的C语言代码回调Java方法. 要想调用实例对象的方法,需要进行以下步骤: 1. 通过对象实例,获取到对象类的引用 => GetO ...
- 【详解】JNI (Java Native Interface) (三)
案例三:C代码访问Java对象的实例变量 获取对象的实例变量的步骤: 1. 通过GetObjectClass()方法获得此对象的类引用 2. 通过类引用的GetFieldID()方法获得实例变量的 ...
- 【详解】JNI (Java Native Interface) (二)
案例二:传递参数给C代码,并从其获取结果 注:这里传递的参数是基本类型的参数,在C代码中有直接的映射类型. 此案例所有生成的所有文件如下: (1)编写案例二的Java代码,如下: 这里我们定义了一个n ...
随机推荐
- singleflight 使用记录以及源码阅读
singleflight 使用方法以及源码阅读 1.简介 安装方式: go get -u golang.org/x/sync/singleflight singleflight 是Go官方扩展同步包的 ...
- 使用EFCore的Code First和MySql数据库迁移
1. 感慨一下 随着.net core的持续更新和升级,至少对于从事.net开发的人员和即将踏入这个领域的人来说,我相信大家的热情还是持续高涨的.国内的.net开发生态相比于之前来说,还是大有所好转的 ...
- 自己动手从零写桌面操作系统GrapeOS系列教程——20.汇编语言读硬盘实战
学习操作系统原理最好的方法是自己写一个简单的操作系统. 本讲我们设计一个简单的读硬盘实验.通过一定的方法使硬盘第二个扇区的前3个字节依次为1.2.3,最后3个字节依次为3.2.1,中间的506个字节全 ...
- python3常用模块和方法
1.使用索引反转字符串 str="hello" print(str[::-1]) 2.zip函数获取可迭代对象,将它们聚合到一个元组中,然后返回结果.语法是zip(*iterabl ...
- [ACM]TL-Kruskal
#include<iostream> #include<cstdio> using namespace std; struct edge { int u; int v; int ...
- 【原创】Ubuntu Pro 中的RealTime linux(Real-time Ubuntu/PREEMPT-RT/ubuntu官方PREEMPT-RT)
[原创]Ubuntu Pro 订阅中的realtime linux(Real-time Ubuntu/PREEMPT-RT) 目录 [原创]Ubuntu Pro 订阅中的realtime linux( ...
- 如何申请 Azure OpenAI
一.前言 众所周知 OpenAI ChatGPT 是不对中国开放的,包括香港.就最近一个月的情况来看,陆续有 API 调用被限制.大规模账号封禁.关闭注册.无法直接使用银联支付(国内信用卡)等等,使用 ...
- 从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(一)
一.创建ASP.NET Core Web API项目(若项目已创建,则可跳过本节内容) 1.双击打开VS2022. 2.单击"创建新项目",如下图. 3.选择"ASP.N ...
- linux下的一道堆上的格式化字符串漏洞题分析分享
简单分享一下解题过程. 下载题目,里面有三个文件,如图: DockerFIle文件: net.sh文件: shell文件是一个elf,文件情况: 64位,Full RELO,NX,PIE 丢进IDA看 ...
- PyTorch基础(Numpy & Tensor)
Numpy与Tensor是PyTorch的重要内容 Numpy的使用 Numpy是Python中科学计算的一个基础包,提供了一个多维度的数组对象,数组是由numpy.ndarray类来实现的,是Num ...