IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> JNI的三种引用 -> 正文阅读

[游戏开发]JNI的三种引用

局部引用

通过NewLocalRef和各种JNI接口创建(FindClass、NewObject、GetObjectClass和NewCharArray等)。会阻止GC回收所引用的对象。函数返回后,局部引用所引用的对象(如果Java层没有对返回的局部引用使用)会被JVM自动释放,或调用DeleteLocalRef释放。(*env)->DeleteLocalRef(env,local_ref)

jclass cls_string = (*env)->FindClass(env, "java/lang/String");
jcharArray charArr = (*env)->NewCharArray(env, len);
jstring str_obj = (*env)->NewObject(env, cls_string, cid_string, elemArray);
jstring str_obj_local_ref = (*env)->NewLocalRef(env,str_obj);   // 通过NewLocalRef函数创建
...

如果使用静态变量存储布局引用,则在方法返回或手动释放后,该静态变量会成为野指针。

局部引用虽然会在方法返回(返回到java环境)后自动释放内存,但依然需要手动释放,原因如下:

1、JNI会将创建的局部引用都存储在一个局部引用表中,该局部引用表的最大数量是512。当一个本地方法中,创建了大量的局部引用,会导致局部引用表溢出。
2、局部引用会阻止所引用对象的GC回收,在不使用时,因尽可能的优先释放,避免占用内存。

如下代码依然会导致局部引用表溢出:

#include <jni.h>
#include <string>

jstring NewStringUTF(JNIEnv *env, const char *str) {
	// 方法入栈和出栈后应该会释放,但实际没有释放
    return env->NewStringUTF(str);
}

extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_ndk_ndkdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    jint i = 0;
    std::string hello = "Hello from C++";
    for (i = 0; i < 1000000; i++)
        jstring str = NewStringUTF(env, hello.c_str());

    return NULL;
}


实际上,每当线程从Java环境切换到本地代码上下文时(J2N),JVM会分配一块内存,创建一个局部引用表,这个表用来存放本次本地方法执行中创建的所有的局部引用。每当在本地代码中引用到一个Java对象时,JVM就会在这个表中创建一个 局部引用。比如,实例一中我们调用NewStringUTF()在Java堆中创建一个String对象后,在局部引用表中就会相应新增一个局部引用。

在这里插入图片描述

依赖关系:局部变量 -> 局部引用表中局部引用 -> Java对象

当函数方法出栈,但并没有切换到Java环境时,仅是对局部变量进行清除,不会操作局部引用。

全局引用

调用NewGlobalRef基于局部引用创建,会阻GC回收所引用的对象。可以跨方法、跨线程使用。JVM不会自动释放,必须调用DeleteGlobalRef手动释放(*env)->DeleteGlobalRef(env,g_cls_string);

static jclass g_cls_string;
void TestFunc(JNIEnv* env, jobject obj) {
    jclass cls_string = (*env)->FindClass(env, "java/lang/String");
    g_cls_string = (*env)->NewGlobalRef(env,cls_string);

	// 释放全局引用 (*env)->NewGlobalRef(env, g_cls_string);
}

弱全局引用

调用NewWeakGlobalRef基于局部引用或全局引用创建,不会阻止GC回收所引用的对象,可以跨方法、跨线程使用。引用不会自动释放,在JVM认为应该回收它的时候(比如内存紧张的时候)进行回收而被释放。或调用DeleteWeakGlobalRef手动释放。(*env)->DeleteWeakGlobalRef(env,g_cls_string)

static jclass g_cls_string;
void TestFunc(JNIEnv* env, jobject obj) {
    jclass cls_string = (*env)->FindClass(env, "java/lang/String");
    g_cls_string = (*env)->NewWeakGlobalRef(env,cls_string);
}

弱全局引用可通过(*env)->IsSameObject(env, obj, NULL)判断是否被释放,如果被回收,则返回JNI_TRUE,否则返回JNI_FALSE

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:55:47  更:2022-03-22 20:56:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 18:51:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码