首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >从本机方法返回由JNI创建的本地引用

从本机方法返回由JNI创建的本地引用
EN

Stack Overflow用户
提问于 2015-11-07 02:28:12
回答 2查看 4K关注 0票数 1

JNI reference说

“本地引用在本机方法调用期间有效。它们在本机方法返回后自动释放。

来源:local

我有点迷路了。根据上述,我必须显式调用NewGlobalRef并传递调用NewObject返回的对象。我尝试过这样做,当GC启动时,它似乎不会收集我的引用(就像某些东西仍然保存它们一样)。考虑以下项目:Main.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package lv.example;

import java.io.IOException;
import java.util.ArrayList;

class Main {

    public static void main(String[] args) {
        ArrayList<Object> store = new ArrayList<Object>();
            while(true) {
                Object d = null;
                try {
                    int c = System.in.read();
                    d = Dummy.getWeakGlobalRef();
                    if(c == 'c')
                        store.clear();
                    store.add(d);
                    System.out.println(d);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

    }

}

Dummy.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package lv.example;

class Dummy {

    static {

        System.loadLibrary("dummy");
    }
       native static Dummy getLocalRef();
       native static Dummy getGlobalRef();
       native static Dummy getWeakGlobalRef();

       @Override
       protected void finalize() throws Throwable {
            System.out.println("Finalized");
       }

}

libdummy.so包含本机方法的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
JNIEXPORT jobject JNICALL Java_lv_example_Dummy_getLocalRef (JNIEnv *env, jclass cls) {
    jmethodID id = env->GetMethodID(cls, "<init>", "()V");
    return env->NewObject(cls, id);
}


JNIEXPORT jobject JNICALL Java_lv_example_Dummy_getGlobalRef (JNIEnv *env, jclass cls) {

    jmethodID id = env->GetMethodID(cls, "<init>", "()V");
    return env->NewGlobalRef(env->NewObject(cls, id));
}


JNIEXPORT jobject JNICALL Java_lv_example_Dummy_getWeakGlobalRef (JNIEnv *env, jclass cls) {
    jmethodID id = env->GetMethodID(cls, "<init>", "()V");
    return env->NewWeakGlobalRef(env->NewObject(cls, id));
}

主循环显示的行为对我来说似乎很奇怪: 1)当我调用getWeakGlobalRef或getLocalRef并清除ArrayList时,GC似乎收集了我创建的所有虚拟对象。2)当我调用getGlobalRef时,无论是否清除ArrayList,都不会收集任何对象。

我在这里有点困惑,这是否意味着我可以将本地引用从本地方法返回回Java代码?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-07 06:32:07

JVM需要知道本机代码是否保留了对对象的引用。也就是说,如果对象被删除,C/C++代码是否可能仍然尝试访问它(可能会导致分段错误)。具有全局引用的对象并不是垃圾收集的,因为本机代码已经表明它可能仍然需要它们。具有本地引用的对象可以被垃圾收集,因为创建引用的函数已经返回给java。具有弱全局引用的对象可以被垃圾收集,因为本机代码表明它将使用IsSameObject检查带有弱引用的对象是否已被垃圾收集,以便只有在未被垃圾收集时才能正确地使用该对象。

关于:

这意味着,New*Ref只用于固定本地代码?JVM跟踪“本地引用”到将其分配给Java变量实例的点吗?

跟踪本地引用,直到返回到java为止。将其分配给java变量并不会删除引用,尽管它将独立地防止该对象的垃圾收集。返回的值将在堆栈上有一个引用,防止垃圾收集,直到它被分配给一个java变量,因此返回的对象不需要具有全局引用,除非本机代码可能在返回后访问同一个对象。如果没有本地引用,JVM可能会在执行JNI函数时垃圾收集对象,因为垃圾收集器在另一个线程中运行。通常不需要显式调用New_Ref/Delete_Ref作为

传递给本机方法的所有Java对象(包括作为JNI函数调用结果返回的对象)都会自动添加到注册表(即给定本地引用)。

(引用自references)

你可能需要这么做。

本机函数生成一个线程,该线程在原始线程中将控件返回给java后继续使用该对象。

本机函数将引用的副本存储在某个全局变量中,以便在来自java的后续调用中使用。

您希望在函数运行时显式删除引用,以便在可能需要一段时间的函数期间节省内存。

票数 6
EN

Stack Overflow用户

发布于 2015-11-08 09:55:28

是。JNI本地引用引用对象;您可以返回对该对象的引用。回到Java方面,“本地引用”没有任何意义。

垃圾收集器的工作方式是从一组根"live“引用开始,并将可从它们访问的任何对象标记为"live”。所有其他对象都会被删除。

JNI的本地和全局引用保存在根引用集中。本地引用在创建本地引用的本机方法返回时自动删除。在此之前,您可以(有时也应该)删除本地引用。全局引用在任何时候都由本机代码显式创建和删除。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33581639

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文