JNI - 谁释放了 Java 方法返回的 ByteBuffer?

JNI - Who frees ByteBuffer returned by a Java method?

我明白了Java调用C时,不需要释放GetDirectBufferAddress方法获得的内存。垃圾收集器知道何时回收内存。在我的例子中,我从 C 调用了一个 Java 方法。下面是我的 Java 方法的代码片段:

ByteBuffer processTask() {
   ...
   ByteBuffer retVal = ByteBuffer.allocateDirect(len);
   return retVal;
}

这是我的 C 函数的代码片段:

jobject retVal = invokeProcessTask();
uint8_t* buf = (uint8_t*) env->GetDirectBufferAddress(retVal);

在这种情况下,我认为垃圾收集器不知道何时收集 ByteBuffer 实例。我认为释放此内存将是我的 C 代码的责任。这是正确的吗?如果是这样,我需要调用什么函数来释放它?问候。

你可以调用DeleteLocalRef(),但除非C方法真的很长,否则可能没有必要-运行:GC可以在JNI方法之后随时收集它returns。

JNI 文档似乎没有说清楚。他们确实说 JNI 函数返回的所有 Java 对象都是本地引用,我看不出有任何理由怀疑 JNI 函数是否在更广泛的本机方法调用范围内被调用是否适用。 VM 负责跟踪传递给本机代码的对象,以免在仍在使用时对它们进行 GC,我认为有必要将 "passed" 解释为包括 "returned to".

因此我倾向于同意这样的解释,当一个Java VM被嵌入到一个C程序中,程序通过调用外部的JNI函数来获取一个Java对象的引用Java -> C 本机方法调用的范围,在 C 程序显式释放其引用(至少)之前,所引用的对象和所有可从中访问的对象都没有资格进行 GC。程序可以通过DeleteLocalRef()函数释放局部引用。

还要注意,在任何给定时间,JNI 仅提供有限数量的本地引用以存在于同一 JNI 环境中。该数字可以通过 EnsureLocalCapacity()PushLocalFrame()PopLocalFrame() 进行管理,但您必须注意避免超过它,这在您描述的嵌入场景中可能比它更具风险处于短运行、范围窄的本机方法调用中。