gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 06:31:09 25 4
gpt4 key购买 nike

JNI 引用说明

"Local references are valid for the duration of a native method call. They are freed automatically after the native method returns.

来源: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 都不会收集任何对象。l

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

最佳答案

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

回复:

So this means, that New*Ref is for pinning for native code only? Does JVM track a "local reference" to the point where I assign it to a instance of Java variable?

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

All Java objects passed to the native method (including those that are returned as the results of JNI function calls) are automatically added to the registry(ie given a local reference).

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

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

native 函数生成一个线程,该线程在控制权返回到原始线程中的 java 后继续使用该对象。

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

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

关于java - 从本地方法返回由 JNI 创建的本地引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33581639/

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