Java JNI直接缓冲区。谁负责本机缓冲区释放?

Java JNI直接缓冲区。谁负责本机缓冲区释放?,java,c,java-native-interface,Java,C,Java Native Interface,一方面,假设我们使用env->NewDirectByteBuffer()创建了一个直接字节缓冲区。另一方面,我们有类似的直接缓冲区,但创建时使用了ByteBuffer.allocateDirect()。显然,JVM应该以相同的方式管理这两个对象,包括管理备份本机缓冲区,在第一种情况下由用户提供,在第二种情况下由JVM从本机堆分配 当然,JVM必须在GC’ing第二个对象(用ByteBuffer.allocateDirect()实例化)期间释放备份缓冲区 我的问题是:JVM会在GC’ing第一个对

一方面,假设我们使用
env->NewDirectByteBuffer()
创建了一个直接字节缓冲区。另一方面,我们有类似的直接缓冲区,但创建时使用了
ByteBuffer.allocateDirect()
。显然,JVM应该以相同的方式管理这两个对象,包括管理备份本机缓冲区,在第一种情况下由用户提供,在第二种情况下由JVM从本机堆分配

当然,JVM必须在GC’ing第二个对象(用
ByteBuffer.allocateDirect()实例化)期间释放备份缓冲区

我的问题是:JVM会在GC’ing第一个对象(用
env->NewDirectByteBuffer()实例化)期间尝试释放缓冲区吗

另外,我在JNI文档和SO都没有找到明确的答案。最有用的信息如下:

Direct ByteBuffer对象自动清理其本机缓冲区 但是,它们只能作为Java堆GC的一部分来执行,所以它们不能 自动响应本机堆上的压力


所以看起来JVM会在GC传递期间释放备份缓冲区,但并没有提到deallocator。它是普通的
free()
还是其他什么。

当您调用JNI
NewDirectByteBuffer(void*address,jlong capacity)
时,将使用以下构造函数创建一个
DirectByteBuffer
对象:

private DirectByteBuffer(long addr, int cap) {
    super(-1, 0, cap, cap);
    address = addr;
    cleaner = null;
    att = null;
}
请注意,
cleaner
属性为空

如果通过
ByteBuffer.allocateDirect()
创建
DirectByteBuffer
,则设置
cleaner
属性(请参阅
DirectByteBuffer
的源代码)

现在,cleaner是一个实用程序对象,其
clean
方法在缓冲区被垃圾收集时运行(有关详细信息,请参阅此)

对于通过
ByteBuffer.allocateDirect()
构建的缓冲区,清理器释放直接内存


对于JNI构造的缓冲区,不执行此类操作。您需要自己释放此内存。

清除。看起来安卓也使用同样的方法。Android SDK有详尽的注释:
/***表示我们不拥有的内存块。(我们不拥有与JNI NewDirectByteBuffer函数创建的直接缓冲区相对应的*内存。)*/
这是最近最好的QnA之一,似乎没有人知道这一点。