JNI reference说
“本地引用在本机方法调用期间有效。它们在本机方法返回后自动释放。
来源: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)当我调用getWeakGlobalRef或getLocalRef并清除ArrayList时,GC似乎收集了我创建的所有虚拟对象。2)当我调用getGlobalRef时,无论是否清除ArrayList,都不会收集任何对象。
我在这里有点困惑,这是否意味着我可以将本地引用从本地方法返回回Java代码?
发布于 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的后续调用中使用。
您希望在函数运行时显式删除引用,以便在可能需要一段时间的函数期间节省内存。
发布于 2015-11-08 09:55:28
是。JNI本地引用引用对象;您可以返回对该对象的引用。回到Java方面,“本地引用”没有任何意义。
垃圾收集器的工作方式是从一组根"live“引用开始,并将可从它们访问的任何对象标记为"live”。所有其他对象都会被删除。
JNI的本地和全局引用保存在根引用集中。本地引用在创建本地引用的本机方法返回时自动删除。在此之前,您可以(有时也应该)删除本地引用。全局引用在任何时候都由本机代码显式创建和删除。
https://stackoverflow.com/questions/33581639
复制相似问题