从本地方法返回由 JNI 创建的本地引用
Returning local reference created by JNI from a native method
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 的调用传递对象 returned。
我试过了,似乎当 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 包含 native 方法的实现:
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 或 not.l
,都不会收集任何对象
我在这里有点困惑,这是否意味着我可以 return 从本地方法返回到 Java 代码的本地引用?
JVM 需要知道本机代码是否保留了它自己对对象的引用。也就是说,如果对象被删除,C/C++ 代码是否有可能仍然尝试访问它(可能导致段错误)。具有全局引用的对象不会被垃圾回收,因为本机代码表明它可能仍然需要它们。具有本地引用的对象可以被垃圾回收,因为创建引用的函数已经 return 编辑为 java。具有弱全局引用的对象可以被垃圾回收,因为本机代码已指示它将使用 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?
跟踪本地引用,直到 return 到 java。将它分配给 java 变量不会删除引用,尽管它会独立地阻止该对象的垃圾收集。 returned 值将在堆栈上有一个引用,防止垃圾收集,直到它可以分配给一个 java 变量,所以 returned 对象不需要有一个全局引用除非本机代码可能会在 return 之后访问同一对象。如果没有本地引用,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).
您可能需要这样做的情况。
本机函数生成一个线程,该线程在原始线程中的控制 returned 到 java 后继续使用该对象。
本机函数将引用的副本存储在某个全局变量中,以供来自 java 的后续调用使用。
您想在函数执行期间显式删除引用 运行 在可能需要一段时间的函数期间节省内存。
是的。 JNI 本地引用引用一个对象;您可以 return 对该对象的引用。回到Java这边,"local reference"没有任何意义。
垃圾收集器的工作方式是从一组根 "live" 引用开始并将从它们可访问的任何对象标记为 "live"。所有其他对象都可能被删除。
JNI 的本地和全局引用保存在根引用集中。当创建它们的本机方法 return 时,本地引用会自动删除。您可以并且有时应该在此之前删除本地引用。本地代码随时显式创建和删除全局引用。
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 的调用传递对象 returned。 我试过了,似乎当 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 包含 native 方法的实现:
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 或 not.l
,都不会收集任何对象我在这里有点困惑,这是否意味着我可以 return 从本地方法返回到 Java 代码的本地引用?
JVM 需要知道本机代码是否保留了它自己对对象的引用。也就是说,如果对象被删除,C/C++ 代码是否有可能仍然尝试访问它(可能导致段错误)。具有全局引用的对象不会被垃圾回收,因为本机代码表明它可能仍然需要它们。具有本地引用的对象可以被垃圾回收,因为创建引用的函数已经 return 编辑为 java。具有弱全局引用的对象可以被垃圾回收,因为本机代码已指示它将使用 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?
跟踪本地引用,直到 return 到 java。将它分配给 java 变量不会删除引用,尽管它会独立地阻止该对象的垃圾收集。 returned 值将在堆栈上有一个引用,防止垃圾收集,直到它可以分配给一个 java 变量,所以 returned 对象不需要有一个全局引用除非本机代码可能会在 return 之后访问同一对象。如果没有本地引用,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).
您可能需要这样做的情况。
本机函数生成一个线程,该线程在原始线程中的控制 returned 到 java 后继续使用该对象。
本机函数将引用的副本存储在某个全局变量中,以供来自 java 的后续调用使用。
您想在函数执行期间显式删除引用 运行 在可能需要一段时间的函数期间节省内存。
是的。 JNI 本地引用引用一个对象;您可以 return 对该对象的引用。回到Java这边,"local reference"没有任何意义。
垃圾收集器的工作方式是从一组根 "live" 引用开始并将从它们可访问的任何对象标记为 "live"。所有其他对象都可能被删除。
JNI 的本地和全局引用保存在根引用集中。当创建它们的本机方法 return 时,本地引用会自动删除。您可以并且有时应该在此之前删除本地引用。本地代码随时显式创建和删除全局引用。