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:
I'm kind of lost here. According to above, I must explicitly call NewGlobalRef and pass object returned from a call to NewObject. I tried this and it seems that when a GC kicks in, it does not collect my references (like something still holds onto them). Consider the following project: 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 包含 native 方法的实现:
libdummy.so contains implementation of native methods:
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 似乎收集了我所有的 Dummy 对象已创建.2)当我调用getGlobalRef时,无论我是否清除ArrayList,都不会收集任何对象.l
Behaviour that main loop exhibits seems strange to me: 1) When I call getWeakGlobalRef or getLocalRef and clear ArrayList, GC seems to collect all the Dummy objects I've created. 2) When I call getGlobalRef, no objects get collected regardless if I clear ArrayList or not.l
我有点困惑,这是否意味着我可以将本地方法中的本地引用返回给 Java 代码?
I'm kind of confused here, does that mean that I can return local references from native methods back to Java code?
JVM 需要知道本机代码是否保留了自己对对象的引用.也就是说,如果对象被删除,C/C++ 代码是否仍然可以尝试访问它(可能导致段错误).具有全局引用的对象不会被垃圾回收,因为本机代码表明它可能仍需要它们.具有本地引用的对象可以被垃圾回收,因为创建引用的函数已经返回给 java.具有弱全局引用的对象可以被垃圾收集,因为本机代码已指示它将使用 IsSameObject 来检查具有弱引用的对象是否已被垃圾收集,以便只有在对象尚未被垃圾收集时才能正确使用该对象.
The JVM needs to know whether the native code is keeping its own references to the objects. That is if the object were deleted, is it possible for the C/C++ code to still try access it (probably causing a segfault). The objects with global references are not garbage collected because the native code has indicated that it might still need them. The objects with local references can be garbage collected because the function where the references were created has already returned to java. The objects with weak global references can be garbage collected because the native code has indicated it will use IsSameObject to check if the object with the weak reference has been garbage collected so that it will behave correctly using the object only if it has not been garbage collected.
回复:
所以这意味着 New*Ref 仅用于固定本机代码?JVM 是否跟踪本地引用"到我将其分配给 Java 变量实例的点?
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.将其分配给 java 变量不会删除引用,尽管它会独立地阻止对该对象的垃圾收集.返回的值将在堆栈上有一个引用,以防止垃圾收集,直到可以将其分配给 java 变量,因此返回的对象不需要具有全局引用,除非本机代码在返回后可能访问同一个对象.如果没有本地引用,JVM 可能会在 JNI 函数执行时对对象进行垃圾收集,因为垃圾收集器在另一个线程中运行.通常不需要显式调用 NewRef/DeleteRef as
Local references are tracked until the return to java. Assigning it to a java variable doesn't remove the reference although it would independently prevent garbage collection of that object. The returned value would have a reference on the stack preventing garbage collection until it could be assigned to a java variable so there is no need for a returned object to have a global reference unless the native code might access that same object after the return. Without the local reference the JVM might garbage collect the object while the JNI function were executing since the garbage collector runs in another thread. Normally one doesn't need to explicitly call NewRef/DeleteRef as
所有传递给本地方法的Java 对象(包括那些作为JNI 函数调用的结果返回的对象)都会自动添加到注册表中(即,给定一个本地引用).
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)
您可能需要这样做的案例.
Cases you might need to do it.
native 函数生成一个线程,该线程在控制权返回给原始线程中的 java 后继续使用该对象.
The native function spawns a thread that continues using the object after control is returned to java in the original thread.
本机函数将引用的副本存储在某个全局变量中,以供后续从 java 调用中使用.
The native function stores a copy of the reference in some global variable for use in subsequent calls from java.
您希望在函数运行时显式删除引用,以在可能需要一段时间的函数期间节省内存.
You want to explicitly delete references while the function is running to conserve memory during a function that might take a while.
这篇关于从本地方法返回由 JNI 创建的本地引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!