gpt4 book ai didi

【GiraKoo】JavaNativeInterface(JNI)的空间(引用)管理

转载 作者:我是一只小鸟 更新时间:2023-05-18 14:31:09 26 4
gpt4 key购买 nike

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

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

1、全局引用(Global References)

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

函数原型

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

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

                        
                      

2、局部引用(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版本中,提供了 EnsureLocalCapacity PushLocalFrame PopLocalFrame NewLocalRef 函数,支持更加复杂的局部引用生命周期能力。

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

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

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

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

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

4、常见问题

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* 空间.

参考文章

  • JNI Functions (oracle.com)

最后此篇关于【GiraKoo】JavaNativeInterface(JNI)的空间(引用)管理的文章就讲到这里了,如果你想了解更多关于【GiraKoo】JavaNativeInterface(JNI)的空间(引用)管理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com