Java JNI 引用类型,传递 ByteBuffers

Java JNI Reference Types, passing ByteBuffers around

我在本机中创建和分配 DirectByteBuffer。然后我将其传递回 Java。由于 DirectByteBuffer 是在 C 中分配的,它驻留在堆内存中并且是 "immune" 到 Java 的垃圾收集器,对吧?从 C 中释放它的唯一方法是使用 free()?

但是在 JNI returns1 中对缓冲区对象调用 (*env)->GetObjectRefType(),这意味着它是本地引用。据说当 JNI 方法 returns 时,Java 的 GC 会自动释放本地引用。有人可以澄清在这种情况下 GC 释放了什么,我应该使用 (*env)->NewGlobalRef(env, bb) 将分配的缓冲区转换为全局引用吗?

C:

JNIEXPORT jobject JNICALL Java_main_Main_byteBufferTest2(JNIEnv *env, jobject obj){
    double *dp = malloc(sizeof(double)*100);
    jobject bb = (*env)->NewDirectByteBuffer(env, (void*)dp, sizeof(double)*100);
    return bb;
}

Java:

ByteBuffer dbb = byteBufferTest2();

对我的回答持怀疑态度,因为太久远了。

I create and allocate DirectByteBuffer in native. I then pass this back to Java. Since DirectByteBuffer is allocated in C

这不完全正确。您使用 (*env)->NewDirectByteBuffer 分配了 bb,所以它是 JNI。

您使用 malloc 分配了 dp,这是另一回事。 bb 是一个 Java 对象包装 dp.

But a call to (*env)->GetObjectRefType() on the buffer object in JNI returns 1, meaning it's a local reference. Local references are said to be automatically freed by Java's GC when JNI method returns.

这是有道理的。字节缓冲区 bb 被释放,它的底层内存 dp 没有。

should i use the (*env)->NewGlobalRef(env, bb) to turn the allocated buffer into Global ref?

我想是的。

JNI 方法 return 时释放本地引用。但是,如果您 return 对 Java 代码的本地引用,显然 Java 代码现在有一个引用。 对象可以垃圾收集当没有更多引用时。这不是一回事.

Since DirectByteBuffer is allocated in C, it resides in heap memory and is "immune" to Java's garbage collector, right?

错了。

The only way to free it is from C using free()?

错了。它是一个 Java 对象,并且像任何其他 Java 对象一样受到 GC 的影响。如果您尝试 free() 它,您将遇到崩溃。

But a call to (*env)->GetObjectRefType() on the buffer object in JNI returns 1, meaning it's a local reference.

正确。

Local references are said to be automatically freed by Java's GC when JNI method returns.

没有。您正在混淆对象和引用。该引用由 JNI 释放。当没有更多引用时,可以释放对象

Should i use the (*env)->NewGlobalRef(env, bb) to turn the allocated buffer into Global ref?

除非您想在后续的 JNI 方法中再次使用它而不将其作为参数传递,否则不会。