当前位置: 首页 > 面试题库 >

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

昌栋
2023-03-14
问题内容

JNI参考资料指出

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

来源:http
:
//docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#global_local

我有点迷路了。根据上述内容,我必须显式调用 NewGlobalRef 并将从调用返回的对象传递给 NewObject
。我尝试了这一点,看来当启动GC时,它不会收集我的引用(就像仍然保留了它们)。考虑以下项目: Main.java

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

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包含 本机 方法的实现:

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)当我调用 getWeakGlobalRefgetLocalRef 并清除 ArrayList时
,GC似乎会收集我创建的所有 Dummy 对象。2)当我打电话getGlobalRef,没有对象得到收集不管我清楚 的ArrayList
或not.l

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


问题答案:

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

回覆:

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

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

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

(引自
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#implementing_local_references)

您可能需要这样做的情况。

在原始线程中将控制权返回给Java之后,本机函数会生成一个继续使用该对象的线程。

本机函数将引用的副本存储在某个全局变量中,以供后续从Java调用使用。

您想在函数运行时显式删除引用,以节省可能需要一段时间的函数。



 类似资料:
  • JNI参考文献中说 “本地引用在本机方法调用期间有效。它们在本机方法返回后自动释放。 资料来源:http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#global_local 我有点迷路了。根据上述内容,我必须显式调用NewGlobalRef并传递从调用NewObject返回的对象。我试过这个,似

  • 打开命令行,执行: cd ~/desktop mkdir wenjiangs-lemp cd wenjiangs-lemp mkdir app vagrant init centos/7 用编辑器打开 wenjiangs-lemp 目录,编辑 Vagrant 配置文件:Vagrantfile macOS: Vagrant.configure("2") do |config| config.v

  • 我是JNI的新手,我正在努力解决这个问题。 我有一个c回调被网络库(alljoyn)调用。 在这个回调中,我需要调用Java代码。 由于此回调位于另一个线程中,因此我使用以下代码获取JNIEnv指针: (jvm是全局指针) 问题是,当我尝试使用此env指针调用FindClass时,结果为NULL。 如果我在主线程中执行完全相同的FindClass调用,一切都会正常工作。 我怎样才能解决这个问题?这

  • 我的角度控制器中有一个对象数组。 我想返回数组中字段的索引值,该字段具有与我的参数匹配的 ID。 数组中只有一个具有匹配 的对象。

  • 问题内容: 我目前有一种方法可以检查3x3网格中中心项周围的内容,如果8个相邻位置中的内容包含我要检查的内容,我想在长度为7的数组上将该正方形标记为1。 为此,我需要在我的方法中创建并返回一个数组,这可能吗? 问题答案: 不知道是什么问题。你是这个意思?

  • 问题内容: 我有一个方法: 由javah C / C ++头生成的此方法是: 如何从jobject(即ByteBuffer实例)获取数据数组? 问题答案: 假设您使用ByteBuffer.allocateDirect()分配了ByteBuffer,则可以使用GetDirectBufferAddress